stream_socket_client():SSL 操作失败,代码为 1

stream_socket_client():SSL 操作失败,代码为 1

我最近将服务器从 Ubuntu 16.04 升级到 20.04,自升级以来,当我尝试通过 SMTP 发送邮件或尝试使用 PHP 7.0 连接到 S3 存储桶时收到以下错误。

stream_socket_client(): SSL operation failed with code 1. OpenSSL Error messages:
error:14161044:SSL routines:state_machine:internal error

我尝试了 Stack Exchange 上的每一个解决方案,但运气不佳。我尝试将以下内容添加到我的 openssl.cnf 中:

openssl_conf = default_conf

[default_conf]
ssl_conf = ssl_sect

[ssl_sect]
system_default = system_default_sect

[system_default_sect]
MinProtocol = TLSv1.2
CipherString = DEFAULT:@SECLEVEL=1

然而这并没有帮助并且我仍然收到这些错误。

任何帮助将不胜感激。

答案1

从 php 5.5 迁移到 php 5.6 后,我在 PHPMailer 中遇到了这个问题。该问题与 openssl 使用的默认 TLS 版本有关。我不是 openssl 专家,但这是对我有用的解决方案。

我的 php 错误日志中记录的错误是

PHP Warning:  stream_socket_enable_crypto(): SSL operation failed with code 1. OpenSSL Error messages:\nerror:14161044:SSL routines:state_machine:internal error in /var/www/XXXXXX/XXXXXX/PHPMailer/class.smtp.php on line 319

class.smtp.phpPHPMailer 中第 319 行的代码使用了 crypto_type STREAM_CRYPTO_METHOD_TLS_CLIENT

if (! stream_socket_enable_crypto ( $this->smtp_conn, true, STREAM_CRYPTO_METHOD_TLS_CLIENT )) {
  return false;
}

我将 crypto_type 从 更改STREAM_CRYPTO_METHOD_TLS_CLIENTSTREAM_CRYPTO_METHOD_TLSv1_2_CLIENT,请参阅 php 文档以了解可用的 crypto_typeshttps://www.php.net/manual/en/function.stream-socket-enable-crypto.php

if (! stream_socket_enable_crypto ( $this->smtp_conn, true, STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT )) {
 return false;
}

此更改帮我解决了错误。我不确定此问题是否是由于 OpenSSL 升级(OpenSSL 1.0.1f 到 OpenSSL 1.1.1f)或 PHP 升级(PHP 5.5.9 到 PHP 5.6.4)引起的

在找到此解决方案之前,我尝试了许多其他更改。因此,这些更改可能也对我的最终解决方案有所贡献。

  1. 我尝试在 PHPMailer 中设置以下内容,但没有奏效
$mail->SMTPOptions = array(
    'ssl' => array(
        'verify_peer' => false,
        'verify_peer_name' => false,
        'allow_self_signed' => true,
        'crypto_method' => STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT
    )
);
  1. 另外,我向 openssl.cnf 添加了以下内容,但这也不起作用
openssl_conf = default_conf 

[default_conf]
ssl_conf = ssl_sect

[ssl_sect]
system_default = system_default_sect

[system_default_sect]
MinProtocol = TLSv1.2
CipherString = DEFAULT:@SECLEVEL=1

答案2

@Swisstone 的答案包含修复程序(使用加密方法STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT),但它仅包含显式调用时的示例stream_socket_enable_crypto。如果直接使用stream_socket_client,则需要定义上下文并将其作为参数传递:

    $contextOptions = array(
        'ssl' => array(
            'crypto_method' => STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT,
        ),
    );
    $context = stream_context_create($contextOptions);
    $sock = stream_socket_client($address, $errno, $errstr, $timeout, STREAM_CLIENT_CONNECT, $context);

相关内容