Start · Sprachen · PHP · Referenz · openssl_pkcs7_sign

openssl_pkcs7_sign

Funktion

Signiert eine S/MIME-Nachricht mit einem X.509-Zertifikat und erstellt eine PKCS#7-signierte Datei.

seit PHP 4.0.6 Kategorie: crypto

Signatur

openssl_pkcs7_sign(string $input_filename, string $output_filename, OpenSSLCertificate|string $certificate, OpenSSLAsymmetricKey|OpenSSLCertificate|array|string $private_key, ?array $headers, int $flags = PKCS7_DETACHED, ?string $untrusted_certificates_filename = null): bool

Beschreibung

openssl_pkcs7_sign liest eine E-Mail-Nachricht oder beliebige Daten aus input_filename, signiert sie kryptografisch mit dem angegebenen Zertifikat und privatem Schlüssel und schreibt das Ergebnis in output_filename. Das erzeugte Format ist PKCS#7/S/MIME und wird von gängigen E-Mail-Clients (Outlook, Thunderbird, Apple Mail) unterstützt, um die Authentizität und Integrität der Nachricht zu verifizieren.

Die Signatur kann entweder detached (Standard, PKCS7_DETACHED) oder eingebettet erzeugt werden. Bei detached Signatures bleibt die ursprüngliche Nachricht für nicht-S/MIME-fähige Clients lesbar. Über den Parameter headers können zusätzliche MIME-Header (z. B. From, To, Subject) in die Ausgabedatei eingefügt werden.

Mit untrusted_certificates_filename lässt sich optional ein PEM-Bündel mit Zwischenzertifikaten angeben, die der Empfänger zur Verifikation der Zertifikatskette benötigt. Dies ist wichtig, wenn das Signierzertifikat nicht von einer allgemein bekannten Root-CA direkt ausgestellt wurde.

Typische Anwendungsgebiete sind das automatische Signieren von ausgehenden E-Mails in Unternehmensanwendungen, die Erzeugung rechtssicher nachweisbarer elektronischer Dokumente sowie die Bereitstellung von S/MIME-gesicherten Benachrichtigungen aus Webanwendungen.

Parameter

Name Typ Default Beschreibung
$input_filename Pflicht string Pfad zur Eingabedatei, die die zu signierende Nachricht enthält (üblicherweise eine rohe E-Mail oder ein MIME-Dokument).
$output_filename Pflicht string Pfad zur Ausgabedatei, in die die signierte PKCS#7/S/MIME-Nachricht geschrieben wird.
$certificate Pflicht OpenSSLCertificate|string Das X.509-Signierzertifikat als OpenSSLCertificate-Ressource, PEM-String oder Dateipfad im Format file://pfad/zur/cert.pem.
$private_key Pflicht OpenSSLAsymmetricKey|OpenSSLCertificate|array|string Der zum Zertifikat gehörende private Schlüssel. Kann als OpenSSLAsymmetricKey-Ressource, PEM-String, Dateipfad (file://...) oder als Array [key, passphrase] für passwortgeschützte Schlüssel übergeben werden.
$headers Pflicht ?array null Assoziatives Array mit MIME-Headern, die der Ausgabedatei vorangestellt werden (z. B. ['From' => 'sender@example.com', 'Subject' => 'Test']). Kann null sein, wenn keine Header hinzugefügt werden sollen.
$flags int PKCS7_DETACHED Bitmaske aus PKCS7_*-Konstanten, die das Signierverhalten steuern. PKCS7_DETACHED erzeugt eine externe Signatur; PKCS7_TEXT konvertiert den Nachrichtentyp auf text/plain.
$untrusted_certificates_filename ?string null Optionaler Pfad zu einer PEM-Datei mit Zwischenzertifikaten (Intermediate CA Certificates), die in die signierte Nachricht eingebettet werden, damit der Empfänger die vollständige Zertifikatskette aufbauen kann.

Rückgabewert

Typ
bool
Beschreibung
Gibt true bei Erfolg zurück. Im Fehlerfall wird false zurückgegeben, z. B. wenn Eingabedatei nicht lesbar, Ausgabedatei nicht schreibbar, Zertifikat oder Schlüssel ungültig oder Schlüssel und Zertifikat nicht zusammenpassen.

Beispiele

Einfaches Signieren einer E-Mail-Nachricht

<?php
// Eingabedatei mit roher E-Mail-Nachricht vorbereiten
$inputFile  = '/tmp/mail_input.eml';
$outputFile = '/tmp/mail_signed.eml';

file_put_contents($inputFile, "Content-Type: text/plain\r\n\r\nHello, this is a signed message.");

// Zertifikat und privaten Schlüssel laden
$certPem    = file_get_contents('/etc/ssl/my_cert.pem');
$privateKey = ['file:///etc/ssl/my_key.pem', 'geheimesPasswort'];

$headers = [
    'From'    => 'sender@example.com',
    'To'      => 'recipient@example.com',
    'Subject' => 'Signierte Testnachricht',
];

$result = openssl_pkcs7_sign(
    $inputFile,
    $outputFile,
    $certPem,
    $privateKey,
    $headers,
    PKCS7_DETACHED
);

if ($result) {
    echo "Nachricht erfolgreich signiert: " . $outputFile . PHP_EOL;
} else {
    echo "Fehler beim Signieren!" . PHP_EOL;
    while ($msg = openssl_error_string()) {
        echo $msg . PHP_EOL;
    }
}
Nachricht erfolgreich signiert: /tmp/mail_signed.eml

Signieren mit Zwischenzertifikaten für vollständige Zertifikatskette

<?php
$inputFile     = '/tmp/document.eml';
$outputFile    = '/tmp/document_signed.eml';
$intermCaFile  = '/etc/ssl/intermediate_ca_bundle.pem';

file_put_contents($inputFile, "Content-Type: text/plain\r\n\r\nDokument mit vollständiger Zertifikatskette.");

$cert       = 'file:///etc/ssl/my_cert.pem';
$privateKey = 'file:///etc/ssl/my_key_nopass.pem';

$headers = [
    'From'    => 'noreply@company.com',
    'To'      => 'partner@external.com',
    'Subject' => 'Offizielles Dokument',
];

$success = openssl_pkcs7_sign(
    $inputFile,
    $outputFile,
    $cert,
    $privateKey,
    $headers,
    PKCS7_DETACHED,
    $intermCaFile
);

if ($success) {
    echo "Signiert mit eingebetteter Zertifikatskette." . PHP_EOL;
    echo "Ausgabegröße: " . filesize($outputFile) . " Bytes" . PHP_EOL;
} else {
    foreach (openssl_error_string() ? [openssl_error_string()] : [] as $err) {
        echo "OpenSSL-Fehler: $err" . PHP_EOL;
    }
}
Signiert mit eingebetteter Zertifikatskette. Ausgabegröße: 4821 Bytes

// Wichtig · Fallstricke

Sicherheitshinweise:

  • Der private Schlüssel sollte niemals im Web-Root oder in einem über HTTP erreichbaren Verzeichnis gespeichert werden. Verwende restriktive Dateisystemberechtigungen (z. B. chmod 400).
  • Passwörter für passwortgeschützte Schlüssel sollten aus Umgebungsvariablen oder einem sicheren Secret-Store gelesen werden, nicht hartcodiert im Quellcode stehen.
  • Temporäre Eingabe- und Ausgabedateien in /tmp sollten nach Verwendung mit unlink() gelöscht werden, insbesondere auf geteilten Systemen.
  • Stelle sicher, dass Zertifikat und privater Schlüssel zusammenpassen – andernfalls schlägt die Funktion mit einem OpenSSL-Fehler fehl. Fehlermeldungen lassen sich über openssl_error_string() in einer Schleife abfragen.
  • Ab PHP 8.0 werden Ressourcen für Schlüssel und Zertifikate durch dedizierte Objekte (OpenSSLCertificate, OpenSSLAsymmetricKey) ersetzt; veraltete resource-Typen werden nicht mehr unterstützt.