Openssl pkcs7 sign: примеры (PHP)

Работа с цифровыми подписями через openssl_pkcs7_sign
Раздел: Шифрование (OpenSSL)
openssl_pkcs7_sign(string $input_filename, string $output_filename, OpenSSLCertificate|string $certificate, OpenSSLAsymmetricKey|OpenSSLCertificate|array|string $private_key, array|null $headers, int $flags = PKCS7_DETACHED, ?string $untrusted_certificates_filename = null): bool

Основные сведения о функции

Назначение

Функция openssl_pkcs7_sign создает цифровую подпись в формате PKCS#7 (S/MIME) для указанного файла. Она применяется для обеспечения целостности и аутентичности электронных документов, сообщений email или любых данных, представленных в виде файла. Типичные сценарии использования включают подпись юридических документов, защищённую почтовую переписку и верификацию источников данных.

Аргументы функции

input_filename (string) — путь к исходному файлу, который требуется подписать.

output_filename (string) — путь к файлу, в который будет сохранен результат с подписью.

certificate (OpenSSLCertificate|string) — сертификат X.509, используемый для подписи. Может быть путём к файлу, строкой PEM или объектом OpenSSLCertificate.

private_key (OpenSSLAsymmetricKey|OpenSSLCertificate|array|string) — закрытый ключ, соответствующий сертификату. Может быть путём к файлу, строкой PEM, массивом с паролем или объектом ключа.

headers (array|null) — массив заголовков, которые добавляются перед данными в подписанном файле. Часто используется для email-заголовков.

flags (int) — комбинация констант, изменяющих поведение подписи. Основные флаги: PKCS7_DETACHED, PKCS7_BINARY, PKCS7_NOATTR, PKCS7_NOCERTS, PKCS7_NOCHAIN, PKCS7_NOSIGS, PKCS7_TEXT.

untrusted_certificates_filename (string|null) — путь к файлу с дополнительными сертификатами (например, промежуточными), которые включаются в подпись.

Примеры использования

Простая подпись файла
// Конфигурация путей и данных
$inputFile = 'document.txt';
$outputFile = 'document_signed.p7s';
$certificate = 'cert.pem';
$privateKey = 'private.key';

// Создание подписи
$success = openssl_pkcs7_sign(
    $inputFile,
    $outputFile,
    $certificate,
    $privateKey,
    [],
    PKCS7_DETACHED
);

if ($success) {
    echo 'Файл подписан.';
} else {
    echo 'Ошибка подписи.';
}
Файл подписан.
Подпись с включением цепочки сертификатов
$success = openssl_pkcs7_sign(
    'data.pdf',
    'data_signed.p7m',
    'cert.pem',
    ['private.key', 'password123'],
    ['From' => 'sender@example.com'],
    PKCS7_NOATTR,
    'chain.pem'
);
var_dump($success);
bool(true)

Похожие функции в PHP

openssl_sign генерирует цифровую подпись для строки данных, но не создаёт контейнер PKCS#7. Её применяют для низкоуровневой подписи произвольных данных.

openssl_cms_sign — более современная функция для подписи в формате CMS (Cryptographic Message Syntax). Она поддерживает актуальные стандарты и рекомендуется для новых проектов вместо openssl_pkcs7_sign.

openssl_pkcs7_encrypt предназначена для шифрования, а не подписи. Её используют совместно с подписью для комплексной защиты данных.

Типичные ошибки

Некорректные пути к файлам
$result = openssl_pkcs7_sign(
    'missing.txt', // файл не существует
    'output.p7s',
    'cert.pem',
    'private.key'
);
var_dump($result);
bool(false)
Неверный формат или пароль ключа
// Передача неправильного пароля для ключа
$result = openssl_pkcs7_sign(
    'file.txt',
    'output.p7s',
    'cert.pem',
    ['private.key', 'wrong_password'] // неверный пароль
);
var_dump($result);
bool(false)

Изменения в версиях PHP

В PHP 8.0 типы параметров certificate и private_key стали строже: вместо ресурсов теперь ожидаются объекты OpenSSLCertificate и OpenSSLAsymmetricKey. Это повышает безопасность и ясность кода.

В PHP 8.1 улучшены сообщения об ошибках, связанных с некорректными аргументами.

Расширенные примеры

Подпись с добавлением временной метки

Для добавления метки времени требуется внешний сервис (TSA). Пример показывает подготовку данных для TSA.

Пример php
// Подпись с флагом PKCS7_NOCERTS и последующее добавление метки
$flags = PKCS7_DETACHED | PKCS7_NOCERTS;
$success = openssl_pkcs7_sign(
    'invoice.xml',
    'invoice_tmp.p7s',
    'cert.pem',
    'private.key',
    [],
    $flags
);
if ($success) {
    // Здесь обычно отправляется запрос к TSA
    echo 'Подпись создана, можно добавить метку времени.';
}
Создание подписи в бинарном формате
Пример php
// Использование флага PKCS7_BINARY
$success = openssl_pkcs7_sign(
    'image.jpg',
    'image_signed.p7m',
    'cert.pem',
    'private.key',
    [],
    PKCS7_BINARY
);
if ($success) {
    echo 'Бинарная подпись создана.';
}
Подпись с несколькими дополнительными сертификатами
Пример php
// Файл chain.pem содержит несколько сертификатов
$success = openssl_pkcs7_sign(
    'report.pdf',
    'report_signed.p7s',
    'cert.pem',
    'private.key',
    [
        'Content-Type' => 'application/pdf',
        'Content-Disposition' => 'attachment'
    ],
    PKCS7_DETACHED,
    'chain.pem' // несколько сертификатов
);
var_dump($success);
bool(true)

Альтернативы в других языках

Python

Модуль cryptography или M2Crypto предоставляет функции для работы с PKCS#7. Пример с cryptography:

from cryptography.hazmat.primitives.serialization import load_pem_private_key
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography import x509

# Загрузка ключа и сертификата
with open('private.key', 'rb') as f:
    private_key = load_pem_private_key(f.read(), password=None)
with open('cert.pem', 'rb') as f:
    cert = x509.load_pem_x509_certificate(f.read())

# Подпись данных (упрощённый пример)
data = b'data to sign'
signature = private_key.sign(data, padding.PKCS1v15(), hashes.SHA256())
JavaScript (Node.js)

Модуль crypto или библиотека pkcs7 могут использоваться для подобных задач.

const crypto = require('crypto');
const fs = require('fs');

// Чтение ключа и сертификата
const privateKey = fs.readFileSync('private.key', 'utf8');
const cert = fs.readFileSync('cert.pem', 'utf8');

// Создание подписи (пример для данных)
const sign = crypto.createSign('SHA256');
sign.update('data to sign');
const signature = sign.sign(privateKey, 'base64');
MySQL

Прямых аналогов в MySQL нет, так как СУБД обычно не предназначены для создания подписей PKCS#7. Для хранения и проверки подписей можно использовать BLOB-поля.

PHP openssl_pkcs7_sign function comments

En
Openssl pkcs7 sign Sign an S/MIME message