Изменения OpenSSL в PHP 5.6.x

Обертки потоков теперь по умолчанию проверяют сертификаты узлов и имена хостов при использовании SSL/TLS

Все шифруемые клиентские потоки теперь по умолчанию включают проверку пиров. По умолчанию используется OpenSSL CA пакет для проверки сертификата пира. В большинстве случаев не требуется ничего делать для соединения с серверами с правильным SSL сертификатом, так как обычно OpenSSL уже настроен для использования хороших CA пакетов.

Стандартный CA пакет может быть переопределен глобально с помощью установки или openssl.cafile или openssl.capath строк конфигурации, или же на уровне каждого запроса используя опции контекста cafile или capath.

Хотя это и не рекомендуется, но можно отклчить проверку сертификата пира для запроса, установив verify_peer опцию контекста в false, и можно отключить проверку имени пира, установив verify_peer_name в false.

Сигнатура сертификата

Была добавлена поддержка извлечения и проверки сигнатуры сертификата. Для извлечения сигнатур сертификатов X.509 добавлена функция openssl_x509_fingerprint(). Также были добавлены две опции контекста потока SSL: capture_peer_cert для захвата узлового сертификата X.509, и peer_fingerprint для проверки сертификата на соответствие заданной сигнатуре.

Обновлены шифры по умолчанию

Список шифров по умолчанию, используемых PHP, был обновлен на более безопасный в соответствии с »  рекомендациями по шифрам от Mozilla, с двумя дополнительными исключениями: анонимные шифры Диффи-Хеллмана и RC4.

Этот список доступен через новую константу OPENSSL_DEFAULT_STREAM_CIPHERS, и может быть переопределен (как и в предыдущих версиях PHP) установкой опцией контекста ciphers.

Сжатие запрещено по умолчанию

Сжатие SSL/TLS было запрещено по умолчанию для compression уменьшения вероятности атаки типа CRIME. В PHP 5.4.13 была добавлена опция контекста disable_compression для возможности запретить компрессию и теперь она по умолчанию установлена как true (то есть компрессия запрещена).

Разрешение серверу определять свой собственный порядок шифров

Была добавлена опция контекста honor_cipher_order, которая позволяет серверу обслуживающему зашифрованный поток самому определять шифры, которыми будет пользоваться клиент. Это позволить снизить риск атаки типа BEAST.

Доступ к согласованному протоколу и шифру

Протокол и шифр, согласованные для шифрованного потока, доступны с помощью функций stream_get_meta_data() или stream_context_get_options(), если опция контекста SSL capture_session_meta установлена как true.

<?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);
?>

Результат выполнения данного примера:

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

Новые возможности для совершенной прямой секретности (PFS) для серверов, обслуживающих шифрованные потоки

Шифрованные потоки клиента уже поддерживают совершенную прямую секретность, поскольку она, как правило, контролируется сервером. Серверы PHP, обслуживающие шифрованные потоки, использующие сертификаты поддерживающие совершенную прямую секретность не нужнаются в каких либо дополнительных действиях для включения PFS; однако, было добавлено некоторое количество новых опций контекста SSL для более точного контроля над PFS и для решения возможных проблем.

ecdh_curve

Эта опция позволяет выбрать кривую для использования в шифрах ECDH. Если не задано, то будет использоваться prime256v1.

dh_param

Путь к файлу, содержащему параметры для обмена ключами Диффи-Хеллмана, созданного, например, с помощью такой команды:

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

Если установлено как true, новая пара ключей будет создана, используя параметры Диффи-Хеллмана, тем самым улучшая прямую секретность.

single_ecdh_use

Если установлено как true, новая пара ключей будет гненерироваться всегда, при согласовании шифра ECDH. Это улучшает прямую секретность.

Выбор версии SSL/TLS

Теперь возможно выбирать конкретную версию SSL и TLS с помощью опции контекста crypto_method или указывая конкретный транспорт при создании обертки потока (например с помощью вызова stream_socket_client() или stream_socket_server()).

Опция контекста SSL crypto_method принимает битовую маску, перечисляющую допустимые протоколы, также как это задается в параметре crypto_type функции stream_socket_enable_crypto().

Выбранная версия протокола и соответствующие опции
Протокол Флаг клиента Флаг сервера Транспорт
Любые версии TLS или SSL STREAM_CRYPTO_METHOD_ANY_CLIENT STREAM_CRYPTO_METHOD_ANY_SERVER ssl://
Любая версия TLS 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

// Требуется TLS 1.0 или выше для использования 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 или 1.2:
$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);

// Соединяемся с использованием транспорта потокового сокета tlsv1.2://
$sock stream_socket_client('tlsv1.2://google.com:443/');

?>

Добавлена функция openssl_get_cert_locations()

Была добавлена функция openssl_get_cert_locations(): она возвращает расположения, в которых PHP будет искать пакеты CA по умолчанию.

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

Результат выполнения данного примера:

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

Была добавлена поддержка для создания, извлечения и проверки подписанных публичных ключей и опознавательных строк (SPKAC). Были добавлены функции openssl_spki_new(), openssl_spki_verify(), openssl_spki_export_challenge() и openssl_spki_export() для создания, проверки экспорта PEM публичных ключей и соответствующих опозновательных строк из SPKAC, созданных из элементов HTML5 KeyGen.

openssl_spki_new

Генерация нового SPKAC с использованием приватного ключа, опозновательной строки и алгоритма хеширования.

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

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

Результат выполнения данного примера:

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

Проверка предоставленного 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

Экспорт связанной опознавательной строки из предоставленного 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;
?>

Результат выполнения данного примера:

challenge string
openssl_spki_export

Экспорт публичного ключа RSA в формате из SPKAC.

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

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

Результат выполнения данного примера:

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