与 gmail SMTP 服务器进行 TLS 握手期间出现 Python 证书错误

问题描述 投票:0回答:1

我编写了一个客户端程序,尝试通过

smtplib
ssl.SSLContext
对象将邮件发送到 Gmail SMTP 服务器,但在 TLS 握手期间加载证书 PEM 文件时出现错误:

import ssl, smtplib, email

def send_email(subject, body, sender, recipients, password):
    mml = email.message.EmailMessage()
    mml.set_content(body)
    mml['From'] = sender
    mml['To'] = ', '.join(recipients)
    mml['Subject'] = subject
    sslctx = ssl.SSLContext(protocol=ssl.PROTOCOL_TLS_CLIENT)
    sslctx.verify_mode = ssl.CERT_REQUIRED
    assert sslctx.verify_mode == ssl.CERT_REQUIRED
    sslctx.load_verify_locations(cafile='crt.pem', capath='.')
    hdlr = smtplib.SMTP(host='smtp.gmail.com', port=587) # do not use SMTP_SSL
    hdlr.starttls(context=sslctx)
    hdlr.login('[email protected]', password)
    hdlr.sendmail(sender, recipients, mml.as_string())
    print("[INFO] Message sent!")


> gmail_demo.send_email(subject='someone testing this site', body='there <b>you</b> go', sender='[email protected]', recipients=['[email protected]'], password='abcdef123456')
>
> Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
  ssl.SSLError: [SSL] PEM lib (_ssl.c:3917)

从该错误消息中,我发现它是由cpython中的C扩展模块报告的,看来方法

SSLContext.load_cert_chain()
是在这里实现的。

我的问题:

  • SSLContext.load_cert_chain(...)
    是否要求调用者提供有效的
    keyfile
    参数?在文档中,参数
    keyfile
    是可选的,但是在C实现中,此错误可能来自于
    SSL_CTX_use_PrivateKey_file(...)
    的返回值。
  • 我的证书文件中有什么不正确的地方吗
    crt.pem
    ?该文件包含我从 gmail SMTP 服务器下载的证书,按照此 google 工作场所管理员帮助中的说明进行操作。

关于环境:CPython 3.12.0

谢谢

python smtp gmail ssl-certificate cpython
1个回答
0
投票

仔细阅读这些文档和这个 stackoverflow 答案后,我发现了我犯的错误:

  • ssl.SSLContext
    中,方法
    load_cert_chain(...)
    是服务器端peer向CA签署证书,然后将服务器证书发送给客户端peer,客户端对它进行验证,在这种情况下需要私钥;但就我而言,不可能拥有 gmail 证书的私钥,我应该使用另一种方法
    load_verify_locations(...)
    ,它只加载证书链。
  • 在我的开发环境中首次连接 gmail SMTP 服务器时,必须准备所有必需的证书。就我而言,证书的颁发者是
    smtp.gmail.com
    google trusted services 1c3
    及其 CA
    google trusted services root R1
    。如 python 文档 中所述,PEM 文件应如下所示:
-----BEGIN CERTIFICATE-----
... (cert for the gmail smtp server)...
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
... (cert for google trusted services 1c3, which signs the gmail server cert)...
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
... (cert for google trusted services root R1, which signs google trusted services 1c3 cert)...
-----END CERTIFICATE-----
© www.soinside.com 2019 - 2024. All rights reserved.