## Изменения 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`

  Экспорт публичного ключа (PEM) 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-----

`↑` and `↓` to navigate • `Enter` to select • `Esc` to close • `/` to open