OpenSSL Änderungen in PHP 5.6.x

Streamwrapper verifizieren nun standardmäßig Zertifikate und Hostnamen bei Verwendung von SSL/TLS

Alle verschlüsselten Clientstreams verifizieren nun standardmäßig den Kommunikationspartner. Standardmäßig wird dafür das Standard-CA-Bundle von OpenSSL zur Verifikation des Peer-Zertifikates herangezogen. In den meisten Fällen sind keine Änderungen notwendig, um mit Servern mit gültigen SSL-Zertifikaten zu kommunizieren, da Distributoren üblicherweise OpenSSL mit vertrauenswürdigen CA-Bundles konfigurieren.

Das Standard-CA-Bundle kann global durch eine Änderung der konfigurationseinstellungen openssl.cafile oder openssl.capath überschrieben werden, oder für einzelne Requests durch die Verwendung der Kontextoptionen cafile oder capath.

Obwohl dies generell nicht empfehlenswert ist, kann die Verifikation der Peer-Zertifikate für einzelne Requests ausgeschaltet werden, indem die Kontextoption verify_peer auf FALSE gesetzt wird. Die Verifikation des Peer-Namen kann durch das Setzen von verify_peer_name auf FALSE ausgeschaltet werden.

Fingerabdrücke von Zertifikaten

Es wurde Unterstützung für das Auslesen und Verifizieren von Fingerabdrücken von Zertifikaten hinzugefügt. openssl_x509_fingerprint() kam hinzu, um den Fingerabdruck aus X.509-Zertifikaten auszulesen und zwei neue SSL Streamkontext-Optionen wurden hinzugefügt: capture_peer_cert zum Auslesen des X.509- Zertifikats des Kommunikationspartners und peer_fingerprint zur Durchsetzung, dass das Zertifikat des Kommunikationspartners dem angegebenen Fingerabdruck entsprechen muss.

Aktualisierung der Standardchiffren

Die von PHP verwendeten Standardchiffren wurden auf eine sicherere Liste aktualisiert, basierend auf den » Mozilla Chiffreempfehlungen, mit zwei zusätzlichen Ausnahmen: anonyme Diffie-Hellman Chiffren und RC4.

Auf diese Liste kann mit der neuen Konstante OPENSSL_DEFAULT_STREAM_CIPHERS zugegriffen und (wie in früheren PHP-Versionen) durch das Setzen der Kontextoption ciphers übersteuert werden.

Komprimierung standardmäßig deaktiviert

Komprimierung von SSL/TLS wurde standardmäßig deaktiviert, um die CRIME-Attacke zu umgehen. PHP 5.4.13 fügte die Kontextoption disable_compression hinzu, um die Komprimierung zu deaktivieren. Dies ist nun standardmäßig auf TRUE (d.h. Komprimierung deaktiviert) gesetzt.

Servern wird erlaubt, die Reihenfolge bevorzugter Chiffren festzulegen

Die SSL Kontextoption honor_cipher_order wurde hinzugefügt, um Servern von verschlüsselten Streams die Umgehung der BEAST-Schwachstelle zu ermöglichen, indem die Chiffren des Servers gegenüber denen des Clients bevorzugt werden.

Zugriff auf ausgehandeltes Protokoll und Chiffre

Auf das Protokoll und die Chiffre, die für einen verschlüsselten Stream ausgehandelt wurden, kann nun mittels stream_get_meta_data() oder stream_context_get_options() zugegriffen werden, wenn die SSL-Kontextoption capture_session_meta auf TRUE gesetzt ist.

<?php
$ctx 
stream_context_create(['ssl' => [
    
'capture_session_meta' => TRUE
]]);

$html file_get_contents('https://google.com/'FALSE$ctx);
$meta stream_context_get_options($ctx)['ssl']['session_meta'];
var_dump($meta);
?>

Das oben gezeigte Beispiel erzeugt folgende Ausgabe:

array(4) {
  ["protocol"]=>
  string(5) "TLSv1"
  ["cipher_name"]=>
  string(20) "ECDHE-RSA-AES128-SHA"
  ["cipher_bits"]=>
  int(128)
  ["cipher_version"]=>
  string(11) "TLSv1/SSLv3"
}

Neue Optionen für Perfect Forward Secrecy bei Servern für verschlüsselte Streams

Verschlüsselte Clientstreams unterstützen Perfect Forward Secrecy bereits, da dies üblicherweise vom Server kontrolliert wird. Es muss nichts zusätzlich unternommen werden, um PFS bei verschlüsselten PHP-Server-Streams zu aktivieren, die Zertifikate verwenden, welche Perfect Forward Secrecy unterstützen. Es wurden jedoch einige neue SSL-Kontextoptionen hinzugefügt, welche mehr Kontrolle über PFS erlauben und eventuell auftretende Kompatibilitätsprobleme behandeln.

ecdh_curve

Diese Option erlaubt die Auswahl einer spezifischen Kurve für ECDH-Chiffren. Falls nicht angegeben, wird prime256v1 verwendet.

dh_param

Pfad zu einer Datei, welche Parameter für den Diffie-Hellman-Schlüsselaustausch enthalt, die beispielsweise durch folgenden Befehl erzeugt werden könnte:

openssl dhparam -out /path/to/my/certs/dh-2048.pem 2048
single_dh_use

Ist dies auf TRUE gesetzt, wird ein neues Schlüsselpaar erzeugt, wenn Diffie-Hellman-Parameter verwendet werden, wodurch sich die Forward Secrecy verbessert.

single_ecdh_use

Ist dies auf TRUE gesetzt, wird immer ein neues Schlüsselpaar erzeugt, wenn ECDH-Chiffren ausgehandelt werden. Dies verbessert die Forward Secrecy.

SSL/TLS Versionsauswahl

Es ist nun möglich die spezifischen Versionen von SSL oder TLS mittels der SSL-Kontextoption crypto_method oder durch die Angabe eines spezifischen Transportes bei der Erzeugung des Streamwrappers auszuwählen (beispielsweise durch den Aufruf von stream_socket_client() oder stream_socket_server()).

Die SSL-Kontextoption crypto_method erwartet eine Bitmaske in der die erlaubten Protokolle aufgezählt sind. Der Parameter crypto_type von stream_socket_enable_crypto() verhält sich genauso.

Ausgewählte Protokollversionen und zugehörige Optionen
Protokoll(e) Client-Flag Server-Flag Transport
Beliebige Version von TLS oder SSL STREAM_CRYPTO_METHOD_ANY_CLIENT STREAM_CRYPTO_METHOD_ANY_SERVER ssl://
Beliebige TLS-Version STREAM_CRYPTO_METHOD_TLS_CLIENT STREAM_CRYPTO_METHOD_TLS_SERVER tls://
TLS 1.0 STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT STREAM_CRYPTO_METHOD_TLSv1_0_SERVER tlsv1.0://
TLS 1.1 STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT STREAM_CRYPTO_METHOD_TLSv1_1_SERVER tlsv1.1://
TLS 1.2 STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT STREAM_CRYPTO_METHOD_TLSv1_2_SERVER tlsv1.2://
SSL 3 STREAM_CRYPTO_METHOD_SSLv3_CLIENT STREAM_CRYPTO_METHOD_SSLv3_SERVER sslv3://
<?php

// Voraussetzen von TLS 1.0 oder neuer bei Verwendung von 
// file_get_contents():
$ctx stream_context_create([
    
'ssl' => [
        
'crypto_method' => STREAM_CRYPTO_METHOD_TLS_CLIENT,
    ],
]);
$html file_get_contents('https://google.com/'false$ctx);

// TLS 1.1 oder 1.2 voraussetzen:
$ctx stream_context_create([
    
'ssl' => [
        
'crypto_method' => STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT |
                           
STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT,
    ],
]);
$html file_get_contents('https://google.com/'false$ctx);

// Verbindung mittels tlsv1.2:// Stream-Socket-Transport.
$sock stream_socket_client('tlsv1.2://google.com:443/');

?>

openssl_get_cert_locations() hinzugefügt

Die Funktion openssl_get_cert_locations() wurde hinzugefügt: Sie gibt den Standard-Ablageort aus, der von PHP bei der Suche von CA-Bundles verwendet wird.

<?php
var_dump
(openssl_get_cert_locations());
?>

Das oben gezeigte Beispiel erzeugt folgende Ausgabe:

array(8) {
  ["default_cert_file"]=>
  string(21) "/etc/pki/tls/cert.pem"
  ["default_cert_file_env"]=>
  string(13) "SSL_CERT_FILE"
  ["default_cert_dir"]=>
  string(18) "/etc/pki/tls/certs"
  ["default_cert_dir_env"]=>
  string(12) "SSL_CERT_DIR"
  ["default_private_dir"]=>
  string(20) "/etc/pki/tls/private"
  ["default_default_cert_area"]=>
  string(12) "/etc/pki/tls"
  ["ini_cafile"]=>
  string(0) ""
  ["ini_capath"]=>
  string(0) ""
}

SPKI-Unterstützung

Unterstützung für die Erzeugung, das Auslesen uns Verifizieren von Signed Public Key And Challenges wurde (SPKAC) wurde hinzugefügt. Die Funktionen openssl_spki_new(), openssl_spki_verify(), openssl_spki_export_challenge() und openssl_spki_export() wurden hinzugefügt, welche die durch ein KeyGen HTML5-Element erzeugten SPKACs erzeugen, verifizieren oder den PEM Public Key und zugehörige Challenge exportieren.

openssl_spki_new

Erzeugt ein neues SPKAC mit einem privaten Schlüssel, Challenge-String und Hashalgorithmus.

<?php
$pkey 
openssl_pkey_new();
openssl_pkey_export($pkey'secret passphrase');

$spkac openssl_spki_new($pkey'challenge string');
?>

Das oben gezeigte Beispiel erzeugt folgende Ausgabe:

SPKAC=MIIBXjCByDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA3L0IfUijj7+A8CPC8EmhcdNoe5fUAog7OrBdhn7EkxFButUp40P7+LiYiygYG1TmoI/a5EgsLU3s9twEz3hmgY9mYIqb/rb+SF8qlD/K6KVyUORC7Wlz1Df4L8O3DuRGzx6/+3jIW6cPBpfgH1sVuYS1vDBsP/gMMIxwTsKJ4P0CAwEAARYkYjViMzYxMTktNjY5YS00ZDljLWEyYzctMGZjNGFhMjVlMmE2MA0GCSqGSIb3DQEBAwUAA4GBAF7hu0ifzmjonhAak2FhhBRsKFDzXdKIkrWxVNe8e0bZzMrWOxFM/rqBgeH3/gtOUDRS5Fnzyq425UsTYbjfiKzxGeCYCQJb1KJ2V5Ij/mIJHZr53WYEXHQTNMGR8RPm7IxwVXVSHIgAfXsXZ9IXNbFbcaLRiSTr9/N4U+MXUWL7
openssl_spki_verify

Verifiziert ein angegebenes SPKAC.

<?php
$pkey 
openssl_pkey_new();
openssl_pkey_export($pkey'secret passphrase');

$spkac openssl_spki_new($pkey'challenge string');
var_dump(openssl_spki_verify($spkac));
?>
openssl_spki_export_challenge

Exportiert eine zugehörige Challenge eines angegebenen SPKAC.

<?php
$pkey 
openssl_pkey_new();
openssl_pkey_export($pkey'secret passphrase');

$spkac openssl_spki_new($pkey'challenge string');
$challenge openssl_spki_export_challenge($spkac):
echo 
$challenge;
?>

Das oben gezeigte Beispiel erzeugt folgende Ausgabe:

challenge string
openssl_spki_export

Exportiert den öffentlichen RSA-Schlüssel eines SPKAC in PEM-Format.

<?php
$pkey 
openssl_pkey_new();
openssl_pkey_export($pkey'secret passphrase');

$spkac openssl_spki_new($pkey'challenge string');
echo 
openssl_spki_export($spkac);
?>

Das oben gezeigte Beispiel erzeugt folgende Ausgabe:

-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDcvQh9SKOPv4DwI8LwSaFx02h7
l9QCiDs6sF2GfsSTEUG61SnjQ/v4uJiLKBgbVOagj9rkSCwtTez23ATPeGaBj2Zg
ipv+tv5IXyqUP8ropXJQ5ELtbXPUN/gvw7cO5EbPHr/7eMhbpw8Gl+AfWxW5hLW8
MGw/+AwwjHBOwong/QIDAQAB
-----END PUBLIC KEY-----