Openssl pkcs7 read: примеры (PHP)
openssl_pkcs7_read(string $data, array &$certificates): boolФункция openssl_pkcs7_read разбирает строку, содержащую данные в формате PKCS#7, и извлекает сертификаты и другие данные в массив. Формат PKCS#7 (также известный как Cryptographic Message Syntax - CMS) применяется для цифровых подписей, шифрования и упаковки сертификатов.
Функция часто используется при обработке S/MIME сообщений, проверке цифровых подписей или извлечении вложенных сертификатов из криптоконтейнеров.
bool openssl_pkcs7_read(string $data, array &$certificates)
- $data (string) - строка с данными в формате PKCS#7. Может содержать как подписанные, так и зашифрованные данные.
- &$certificates (array) - ссылка на массив, который будет заполнен извлеченными сертификатами и другими данными после успешного выполнения функции.
Функция возвращает true при успешном разборе данных и false в случае ошибки.
Разбор простой PKCS#7 структуры:
$pkcs7_data = '-----BEGIN PKCS7-----
MIAGCSqGSIb3DQEHAq...
-----END PKCS7-----'; // Усечено для примера
$certs = [];
if (openssl_pkcs7_read($pkcs7_data, $certs)) {
echo 'Извлечено сертификатов: ' . count($certs);
foreach ($certs as $idx => $cert) {
echo "\nСертификат #$idx:\n";
echo $cert;
}
} else {
echo 'Ошибка чтения PKCS#7 данных';
}Извлечено сертификатов: 2 Сертификат #0: -----BEGIN CERTIFICATE----- MIIDXTCCAkWgAwIBAgIJA... -----END CERTIFICATE----- Сертификат #1: -----BEGIN CERTIFICATE----- MIIDdzCCAl+gAwIBAgI... -----END CERTIFICATE-----
$smime_message = file_get_contents('message.smime');
$certificates = [];
if (openssl_pkcs7_read($smime_message, $certificates)) {
$cert_info = openssl_x509_parse($certificates[0]);
echo 'Владелец сертификата: ' . $cert_info['subject']['CN'];
} else {
echo 'Не удалось прочитать S/MIME сообщение';
}Владелец сертификата: Example Corporation
- openssl_pkcs7_verify() - проверяет подпись PKCS#7. Предпочтительнее при необходимости валидации подписи, а не только извлечения данных.
- openssl_pkcs7_decrypt() - расшифровывает PKCS#7 сообщение. Используется когда данные зашифрованы.
- openssl_x509_read() - парсит отдельный сертификат X.509. Подходит если уже есть извлеченный сертификат в строковом формате.
- openssl_cms_read() (PHP 8.0+) - работает с форматом CMS (более современный аналог PKCS#7). Рекомендуется для новых проектов.
$data = 'Просто текст, а не PKCS#7';
$certs = [];
$result = openssl_pkcs7_read($data, $certs);
var_dump($result); // bool(false)
var_dump($certs); // array(0) {}// При отсутствии расширения возникает фатальная ошибка:
// Fatal error: Uncaught Error: Call to undefined function openssl_pkcs7_read()Решение: убедиться что расширение OpenSSL активировано в php.ini
$certs = [];
// Неправильно - не будет работать в PHP 8+
$result = openssl_pkcs7_read($data, $certs); // Предупреждение- PHP 8.0.0: Функция теперь возвращает false вместо null при ошибке. Тип параметра $certificates строго проверяется - должен быть массивом.
- PHP 7.2.0: Добавлена поддержка дополнительных форматов кодирования.
- Ранние версии: Функция могла некорректно обрабатывать некоторые варианты BER кодировки.
function extractCertificateChain($pkcs7Data) {
$certs = [];
if (!openssl_pkcs7_read($pkcs7Data, $certs)) {
return null;
}
$chain = [];
foreach ($certs as $certPem) {
$certData = openssl_x509_parse($certPem);
if ($certData) {
$chain[] = [
'pem' => $certPem,
'subject' => $certData['subject'],
'issuer' => $certData['issuer'],
'validity' => [
'from' => date('Y-m-d', $certData['validFrom_time_t']),
'to' => date('Y-m-d', $certData['validTo_time_t'])
]
];
}
}
return $chain;
}
// Использование
$chain = extractCertificateChain($pkcs7_data);
if ($chain) {
echo 'Цепочка из ' . count($chain) . ' сертификатов:\n';
foreach ($chain as $i => $cert) {
echo "{$i}. CN: {$cert['subject']['CN']} (до {$cert['validity']['to']})\n";
}
}function deepParsePKCS7($data, &$allCerts = []) {
$currentCerts = [];
if (openssl_pkcs7_read($data, $currentCerts)) {
foreach ($currentCerts as $cert) {
// Проверяем не является ли сертификат на самом деле PKCS#7 контейнером
if (strpos($cert, 'BEGIN PKCS7') !== false) {
deepParsePKCS7($cert, $allCerts);
} else {
$allCerts[] = $cert;
}
}
return true;
}
return false;
}
$allCertificates = [];
deepParsePKCS7($nested_pkcs7_data, $allCertificates);
echo 'Найдено всех сертификатов: ' . count($allCertificates);// Конвертация DER в PEM для openssl_pkcs7_read
$derData = file_get_contents('signature.der');
$pemData = "-----BEGIN PKCS7-----\n" .
chunk_split(base64_encode($derData), 64, "\n") .
"-----END PKCS7-----";
$certs = [];
if (openssl_pkcs7_read($pemData, $certs)) {
echo 'Успешно конвертировано и прочитано';
}$pkcs7Data = file_get_contents('signed_document.p7m');
$certs = [];
if (openssl_pkcs7_read($pkcs7Data, $certs)) {
// Первый элемент часто содержит подписанные данные
$signedData = $certs[0];
// Поиск атрибутов подписи
if (preg_match('/signingTime:(.*?)(?:\n|$)/', $signedData, $matches)) {
echo 'Время подписания: ' . trim($matches[1]);
}
// Извлечение OID атрибутов
$oids = [];
if (preg_all('/OID:(.*?)\n/', $signedData, $oidMatches)) {
$oids = $oidMatches[1];
}
print_r($oids);
}from cryptography.hazmat.primitives.serialization import pkcs7
from cryptography import x509
import base64
# Данные PKCS#7 в формате PEM
pkcs7_data = '-----BEGIN PKCS7-----...'
# Загрузка PKCS#7 данных
pkcs7_obj = pkcs7.load_pem_pkcs7_certificates(pkcs7_data.encode())
print(f"Извлечено {len(pkcs7_obj)} сертификатов")
for cert in pkcs7_obj:
print(cert.subject)const pkcs7 = require('pkcs7');
const fs = require('fs');
const pkcs7Data = fs.readFileSync('signature.p7m', 'binary');
const certs = pkcs7.extractCertificates(pkcs7Data);
console.log(`Извлечено сертификатов: ${certs.length}`);В Python библиотека cryptography предоставляет более объектно-ориентированный интерфейс. В Node.js требуется установка дополнительных модулей. PHP функция встроена в расширение OpenSSL и работает с PEM форматом по умолчанию.