fwrite (): операция SSL не выполнена с кодом 1. Сообщения об ошибках OpenSSL: ошибка: 1420C0CF: процедуры SSL: ssl_write_internal: протокол отключен - PullRequest
1 голос
/ 23 января 2020

Полное название должно быть «PHP - отправка сообщений электронной почты: fwrite (): операция SSL не выполнена с кодом 1. Сообщения об ошибках OpenSSL: ошибка: 1420C0CF: процедуры SSL: ssl_write_internal: протокол выключен - проанализируйте stream_socket_enable_crypto, возвращая false». Но это было слишком долго для 150 символов заголовка.

Мы пытаемся отправить электронное письмо в сценарии PHP, и мы получаем

Warning: fwrite(): SSL operation failed with code 1. OpenSSL Error messages:error:1420C0CF:SSL routines:ssl_write_internal:protocol is shutdown in <...>/vendor/recolize/zendframework1/library/Zend/Mail/Protocol/Abstract.php on line 324 

Как видно выше, мы использование версии адаптации давно устаревшего zendframework1, но это не проблема, так как это работает на двух других хостерах.

Поскольку проблема не детерминирована c, у нас нет способа воспроизвести ее правильно сейчас.

Однако у нас есть тестовый скрипт, который позволяет провести некоторый анализ, но мне нужна помощь, чтобы понять, в чем может быть проблема.

Без лишних слов:

Мы используя сценарий из ответа на этот стек: Как проверить, действителен ли сертификат TLS SMTP в PHP? - Ответ 1

Важная часть заключается в следующем:

// Establish the connection
$smtp = fsockopen( "tcp://$server", 25, $errno, $errstr );
fread( $smtp, 512 );

// Here you can check the usual banner from $server (or in general,
// check whether it contains $server's domain name, or whether the
// domain it advertises has $server among its MX's.
// But yet again, Google fails both these tests.

fwrite($smtp,"HELO $myself\r\n");
fread($smtp, 512);

// Switch to TLS
fwrite($smtp,"STARTTLS\r\n");
fread($smtp, 512);
stream_set_blocking($smtp, true);
stream_context_set_option($smtp, 'ssl', 'verify_peer', true);
stream_context_set_option($smtp, 'ssl', 'allow_self_signed', true);
stream_context_set_option($smtp, 'ssl', 'capture_peer_cert', true);
stream_context_set_option($smtp, 'ssl', 'cafile', $cabundle);

// Necessary block to circumvent https://www.php.net/manual/en/function.stream-socket-enable-crypto.php#119122
$crypto_method = STREAM_CRYPTO_METHOD_TLS_CLIENT;
if (defined('STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT')) {
    $crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT;
    $crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT;
}

$secure = stream_socket_enable_crypto($smtp, true, $crypto_method);

// $secure = stream_socket_enable_crypto($smtp, true, STREAM_CRYPTO_METHOD_TLS_CLIENT );
var_dump($secure);
die;

Установлен сокет, установлено блокирование, заданы параметры SSL и сделана попытка запустить шифрование с использованием PHP s stream_socket_enable_crypto .

stream_socket_enable_crypto, однако возвращает bool (false) и никакой информации о том, почему он не работает.

В настоящее время мы подозреваем, что проверка сертификата почтового сервера не удается, но мы не можем проанализировать его.

Как получить дополнительную информацию, почему stream_socket_enable_crypto возвращает false?

edit1:

Адаптирован код блок выше, чтобы отразить специальность STREAM_CRYPTO_METHOD_TLS_CLIENT, начиная с PHP 5.6.7 , как указано @Dilek ниже. Спасибо за ответ! К сожалению, это не изменило общий результат. $ secure остается bool (false).

edit2:

В ответ на ОБНОВЛЕНИЕ @ Dilek:

$ php ssl_test.php
Array
(
    [ssl] => Array
        (
            [verify_host] => 1
            [verify_peer] => 1
            [allow_self_signed] =>
            [cafile] => /etc/ssl/cert.pem
        )

)
failed to connect securely

Я убедился, что кафе существует :

$ ll /etc/ssl/cert.pem
0 lrwxrwxrwx  1 root  wheel  38 Dec 19 11:09 /etc/ssl/cert.pem -> /usr/local/share/certs/ca-root.crt

и быстро проверил его содержимое, которое выглядит нормально:

Certificate:
    Data:
        Version: ...
        Serial Number:
            ...
        Signature Algorithm: ...
        Issuer: ...
        ...
    Signature Algorithm: ...
-----BEGIN CERTIFICATE-----
MI...6EULg==
-----END CERTIFICATE-----

Certificate:
    Data:
        Version: ...
        Serial Number:
            ...

etc.

Ответы [ 2 ]

2 голосов
/ 23 января 2020

PHP ошибка: https://bugs.php.net/bug.php?id=69195

Фиксация: https://github.com/php/php-src/commit/10bc5fd4c4c8e1dd57bd911b086e9872a56300a0

STREAM_CRYPTO_METHOD_SSLv23_CLIENT небезопасно использовать, потому что раньше php 5.6.7, это означает sslv2 или sslv3. Итак, вы должны сделать это:

$crypto_method = STREAM_CRYPTO_METHOD_TLS_CLIENT;

if (defined('STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT')) {
    $crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT;
    $crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT;
}

stream_socket_enable_crypto($socket, true, $crypto_method);

Вы должны прочитать нижнюю часть страницы, на которую вы ссылались в вопросе.

Документация: https://www.php.net/manual/en/function.stream-socket-enable-crypto.php

ОБНОВЛЕНИЕ: ваш код должен выглядеть следующим образом

            $smtp = fsockopen( "tcp://mail.domain.com", 25, $errno, $errstr );
            fread( $smtp, 512 );
            fwrite($smtp,"HELO worp\r\n");
            fread($smtp, 512);
            fwrite($smtp,"STARTTLS\r\n");
            fread($smtp, 512);
            stream_set_blocking($smtp, true);
            stream_context_set_option($smtp, 'ssl', 'verify_host', true);
            stream_context_set_option($smtp, 'ssl', 'verify_peer', true);
            stream_context_set_option($smtp, 'ssl', 'allow_self_signed', false);

//Self signed certificates are blocked by googl and most servers

            stream_context_set_option($smtp, 'ssl', 'cafile', '/etc/ssl/cacert.pem');
    //you need to add correct and full path of CA file 

    //This is second solution in php documents in the link in question and in my answer
            $secure = stream_socket_enable_crypto($smtp, true, STREAM_CRYPTO_METHOD_TLS_CLIENT);
            stream_set_blocking($smtp, false);
            print_r(stream_context_get_options($smtp));
            if( ! $secure)
                    die("failed to connect securely\n");
            print "Success!\n";

Надеюсь, это поможет вам.

0 голосов
/ 23 января 2020

Окончательный ответ: Используйте EHLO statt HELO при разговоре по SMTP.

Причина: HELO не поддерживает STARTTLS .

Окончательный сценарий:

$smtp = fsockopen( "tcp://mail.noris.net", 25, $errno, $errstr );
fread( $smtp, 512 );
fwrite($smtp,"EHLO test.de\r\n");
fread($smtp, 512);
fwrite($smtp,"STARTTLS\r\n");
fread($smtp, 512);
stream_set_blocking($smtp, true);
stream_context_set_option($smtp, 'ssl', 'verify_host', false);
stream_context_set_option($smtp, 'ssl', 'verify_peer', false);
stream_context_set_option($smtp, 'ssl', 'allow_self_signed', false);

//Self signed certificates are blocked by googl and most servers

stream_context_set_option($smtp, 'ssl', 'cafile', '/etc/ssl/cert.pem');
//you need to add correct and full path of CA file

//This is second solution in php documents in the link in question and in my answer
$secure = stream_socket_enable_crypto($smtp, true, STREAM_CRYPTO_METHOD_TLS_CLIENT);
stream_set_blocking($smtp, false);
print_r(stream_context_get_options($smtp));
if( ! $secure) {
    print("failed to connect securely\n");
}
else {
    print "Success!\n";
}

var_dump($errno);
var_dump($errstr);
die;

Вывод:

$ php ssl_test.php
Array
(
    [ssl] => Array
        (
            [verify_host] =>
            [verify_peer] =>
            [allow_self_signed] =>
            [cafile] => /etc/ssl/cert.pem
        )

)
Success!
int(0)
string(0) ""
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...