"ssl" --- 套接字对象的 TLS/SSL 包装器
*************************************

**源代码:** Lib/ssl.py

======================================================================

本模块保证了对传安全传输层协议（TLS）的访问 (SSL)加密，并且提供客户端
和服务端层面的网络嵌套字层面的对等连接认证技术。本模块使用OpenSSL库。
适用于所有现代Unix系统、Windows以及Mac OS X。只要Open SSL存在的系统，
都有机会正常使用。

備註:

  某些行为可能具有平台依赖，因为调用是根据操作系统的嵌套字API。不同版
  本的Open SSL也会引起差异：例如Open SSL版本1.0.1 自带TLSv1.1 和
  TLSv1.2

警告:

  在阅读 Security considerations 前不要使用此模块。 这样做可能会导致虚
  假的安全感，因为ssl模块的默认设置不一定适合你的应用程序。

本文档记录"ssl"模块的对象和函数；更多关于TLS,SSL,和证书的信息，请参阅
下方的“详情”选项

本模块提供了一个类 "ssl.SSLSocket"，它派生自 "socket.socket" 类型，并
提供类似套接字的包装器，也能够对通过带 SSL 套接字的数据进行加密和解密
。 它支持一些额外方法例如 "getpeercert()"，该方法可从连接的另一端获取
证书，还有 "cipher()"，该方法可获取安全连接所使用的密码。

对于更复杂的应用程序，"ssl.SSLContext" 类有助于管理设置项和证书，进而
可以被使用 "SSLContext.wrap_socket()" 方法创建的 SSL 套接字继承。

3.5.3 版更變: 更新以支持和 OpenSSL 1.1.0 的链接

3.6 版更變: OpenSSL 0.9.8、1.0.0 和 1.0.1 已过时，将不再被支持。在 ssl
模块未来的版本中，最低需要 OpenSSL 1.0.2 或 1.1.0。


方法、常量和异常处理
====================


套接字创建
----------

从 Python 3.2 和 2.7.9 开始，建议使用 "SSLContext" 实例的
"SSLContext.wrap_socket()" 来将套接字包装为 "SSLSocket" 对象。 辅助函
数 "create_default_context()" 会返回一个新的带有安全默认设置的上下文。
旧的 "wrap_socket()" 函数已被弃用，因为它效率较差并且不支持服务器名称
提示（SNI）和主机匹配。

客户端套接字实例，采用默认上下文和IPv4/IPv6双栈:

   import socket
   import ssl

   hostname = 'www.python.org'
   context = ssl.create_default_context()

   with socket.create_connection((hostname, 443)) as sock:
       with context.wrap_socket(sock, server_hostname=hostname) as ssock:
           print(ssock.version())

客户端套接字示例，带有自定义上下文和IPv4:

   hostname = 'www.python.org'
   # PROTOCOL_TLS_CLIENT requires valid cert chain and hostname
   context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
   context.load_verify_locations('path/to/cabundle.pem')

   with socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) as sock:
       with context.wrap_socket(sock, server_hostname=hostname) as ssock:
           print(ssock.version())

服务器套接字实例，在localhost上监听IPv4:

   context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
   context.load_cert_chain('/path/to/certchain.pem', '/path/to/private.key')

   with socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) as sock:
       sock.bind(('127.0.0.1', 8443))
       sock.listen(5)
       with context.wrap_socket(sock, server_side=True) as ssock:
           conn, addr = ssock.accept()
           ...


上下文创建
----------

便捷函数，可以帮助创建 "SSLContext" 对象，用于常见的目的。

ssl.create_default_context(purpose=Purpose.SERVER_AUTH, cafile=None, capath=None, cadata=None)

   返回一个新的 "SSLContext" 对象，使用给定 *purpose* 的默认设置。 该
   设置由 "ssl" 模块选择，并且通常是代表一个比直接调用 "SSLContext" 构
   造器时更高的安全等级。

   *cafile*, *capath*, *cadata* 代表用于进行证书核验的可选受信任 CA 证
   书，与 "SSLContext.load_verify_locations()" 的一致。 如果三个参数均
   为 "None"，此函数可以转而选择信任系统的默认 CA 证书。

   设置包括: "PROTOCOL_TLS", "OP_NO_SSLv2" 以及 "OP_NO_SSLv3"，具有不
   带 RC4 和不带无身份验证密码套件的高度加密密码套件。 传入
   "SERVER_AUTH" 作为 *purpose* 会把 "verify_mode" 设为
   "CERT_REQUIRED" 并且加载指定 CA 证书（当给出 *cafile*, *capath* 和
   *cadata* 中的至少一个）或者使用 "SSLContext.load_default_certs()"
   来加载默认 CA 证书。

   当 "keylog_filename" 受支持并且设置了环境变量 "SSLKEYLOGFILE" 时，
   "create_default_context()" 会启用密钥日志记录。

   備註:

     协议、选项、密码和其他设置可随时更改为更具约束性的值而无须事先弃
     用。 这些值代表了兼容性和安全性之间的合理平衡。如果你的应用需要特
     定的设置，你应当创建一个 "SSLContext" 并自行应用设置。

   備註:

     如果你发现当某些较旧的客户端或服务器尝试与用此函数创建的
     "SSLContext" 进行连接时收到了报错提示 "Protocol or cipher suite
     mismatch"，这可能是因为它们只支持 SSL3.0 而它被此函数用
     "OP_NO_SSLv3" 排除掉了。 SSL3.0 被广泛认为 完全不可用。 如果你仍
     希望继续使用此函数但仍允许 SSL 3.0 连接，你可以使用以下代码重新启
     用它们:

        ctx = ssl.create_default_context(Purpose.CLIENT_AUTH)
        ctx.options &= ~ssl.OP_NO_SSLv3

   3.4 版新加入.

   3.4.4 版更變: RC4 被从默认密码字符串中丢弃。

   3.6 版更變: ChaCha20/Poly1305 被添加到默认密码字符串中。3DES 被从默
   认密码字符串中丢弃。

   3.8 版更變: 增加了对密钥日志记录至 "SSLKEYLOGFILE" 的支持。


异常
----

exception ssl.SSLError

   引发此异常以提示来自下层 SSL 实现（目前由 OpenSSL 库提供）的错误。
   它表示在下层网络连接之上叠加的高层级加密和验证层存在某种问题。 此错
   误是 "OSError" 的一个子类型。 "SSLError" 实例的错误和消息是由
   OpenSSL 库提供的。

   3.3 版更變: "SSLError" 曾经是 "socket.error" 的一个子类型。

   library

      一个字符串形式的助记符，用来指明发生错误的 OpenSSL 子模块，例如
      "SSL", "PEM" 或 "X509"。 可能的取值范围依赖于 OpenSSL 的版本。

      3.3 版新加入.

   reason

      一个字符串形式的助记符，用来指明发生错误的原因，例如
      "CERTIFICATE_VERIFY_FAILED"。 可能的取值范围依赖于 OpenSSL 的版
      本。

      3.3 版新加入.

exception ssl.SSLZeroReturnError

   "SSLError" 的子类，当尝试读取或写入且 SSL 连接已被完全关闭时会被引
   发。 请注意这并不意味着下层的传输（读取 TCP）已被关闭。

   3.3 版新加入.

exception ssl.SSLWantReadError

   "SSLError" 的子类，当尝试读取或写入数据，但在请求被满足之前还需要在
   下层的 TCP 传输上接收更多数据时会被 非阻塞型 SSL 套接字 引发。

   3.3 版新加入.

exception ssl.SSLWantWriteError

   "SSLError" 的子类，当尝试读取或写入数据，但在请求被满足之前还需要在
   下层的 TCP 传输上发送更多数据时会被 非阻塞型 SSL 套接字 引发。

   3.3 版新加入.

exception ssl.SSLSyscallError

   "SSLError" 的子类，当尝试在 SSL 套接字上执行操作时遇到系统错误时会
   被引发。 不幸的是，没有简单的方式能检查原始 errno 编号。

   3.3 版新加入.

exception ssl.SSLEOFError

   "SSLError" 的子类，当 SSL 连接被突然终止时会被引发。 通常，当遇到此
   错误时你不应再尝试重用下层的传输。

   3.3 版新加入.

exception ssl.SSLCertVerificationError

   "SSLError" 的子类，当证书验证失败时会被引发。

   3.7 版新加入.

   verify_code

      一个数字形式的错误编号，用于表示验证错误。

   verify_message

      用于表示验证错误的人类可读的字符串。

exception ssl.CertificateError

   "SSLCertVerificationError" 的别名。

   3.7 版更變: 此异常现在是 "SSLCertVerificationError" 的别名。


随机生成
--------

ssl.RAND_bytes(num)

   返回 *num* 个高加密强度伪随机字节数据。 如果 PRNG 未使用足够的数据
   作为随机种子或者如果当前 RAND 方法不支持该操作则会引发 "SSLError"。
   "RAND_status()" 可被用来检查 PRNG 的状态而 "RAND_add()" 可被用来为
   PRNG 设置随机种子。

   对于几乎所有应用程序都更推荐使用 "os.urandom()"。

   请阅读维基百科文章 Cryptographically secure pseudorandom number
   generator (CSPRNG) 以了解对于高加密强度生成器的具体要求。

   3.3 版新加入.

ssl.RAND_pseudo_bytes(num)

   返回 (bytes, is_cryptographic): bytes 是 *num* 个伪随机字节数据，如
   果所生成的字节数据为高加密强度则 is_cryptographic 为 "True"。 如果
   当前 RAND 方法不支持此操作则会引发 "SSLError"。

   所生成的伪随机字节序列如果具有足够的长度则将会具有唯一性，并是并非
   不可预测。 它们可被用于非加密目的以及加密协议中的特定目的，但通常不
   可被用于密钥生成等目的。

   对于几乎所有应用程序都更推荐使用 "os.urandom()"。

   3.3 版新加入.

   3.6 版後已棄用: OpenSSL 已弃用了 "ssl.RAND_pseudo_bytes()"，请改用
   "ssl.RAND_bytes()"。

ssl.RAND_status()

   如果 SSL 伪随机数生成器已使用‘足够的’随机性作为种子则返回  "True"，
   否则返回 "False"。 你可以使用 "ssl.RAND_egd()" 和 "ssl.RAND_add()"
   来增加伪随机数生成器的随机性。

ssl.RAND_egd(path)

   如果你在某处运行了一个熵收集守护程序（EGD），且 *path* 是向其打开的
   套接字连接路径名，此函数将从该套接字读取 256 个字节的随机性数据，并
   将其添加到 SSL 伪随机数生成器以增加所生成密钥的安全性。 此操作通常
   只在没有更好随机性源的系统上才是必要的。

   请查看 http://egd.sourceforge.net/ 或 http://prngd.sourceforge.net/
   来了解有关熵收集守护程序源的信息。

   可用性: 对于 LibreSSL 和 OpenSSL > 1.1.0 不可用。

ssl.RAND_add(bytes, entropy)

   将给定的 *bytes* 混合到 SSL 伪随机数生成器中。 形参 *entropy*
   (float 类型) 是数据所包含的熵的下界 (因此你可以总是使用 "0.0")。 请
   查看 **RFC 1750** 了解有关熵源的更多信息。

   3.5 版更變: 现在接受可写的 *字节类对象*。


证书处理
--------

ssl.match_hostname(cert, hostname)

   验证 *cert* (使用 "SSLSocket.getpeercert()" 所返回的已解码格式) 是
   否匹配给定的 *hostname*。 所应用的规则是在 **RFC 2818**, **RFC
   5280** 和 **RFC 6125** 中描述的检查 HTTPS 服务器身份的规则。 除了
   HTTPS，此函数还应当适用于各种基于 SSL 协议的服务器身份检查操作，例
   如 FTPS, IMAPS, POPS 等等。

   失败时引发 "CertificateError"。 成功时此函数无返回值:

      >>> cert = {'subject': ((('commonName', 'example.com'),),)}
      >>> ssl.match_hostname(cert, "example.com")
      >>> ssl.match_hostname(cert, "example.org")
      Traceback (most recent call last):
        File "<stdin>", line 1, in <module>
        File "/home/py3k/Lib/ssl.py", line 130, in match_hostname
      ssl.CertificateError: hostname 'example.org' doesn't match 'example.com'

   3.2 版新加入.

   3.3.3 版更變: 此函数现在遵循 **RFC 6125**, 6.4.3 小节，它不会匹配多
   个通配符 (例如 "*.*.com" 或 "*a*.example.org") 也不匹配国际化域名
   (IDN) 片段内部的通配符。 IDN A 标签例如 "www*.xn--pthon-kva.org" 仍
   然受支持，但 "x*.python.org" 不再能匹配 "xn--tda.python.org"。

   3.5 版更變: 现在支持匹配存在于证书的 subjectAltName 字段中的 IP 地
   址。

   3.7 版更變: 此函数不再被用于 TLS 连接。 主机匹配现在是由 OpenSSL 执
   行的。允许位于段的最左端且为唯一字符的通配符。 部分通配符例如
   "www*.example.com" 已不再受支持。

   3.7 版後已棄用.

ssl.cert_time_to_seconds(cert_time)

   返回距离 Unix 纪元零时的秒数，给定的 "cert_time" 字符串代表来自证书
   的 "notBefore" 或 "notAfter" 日期值，采用 ""%b %d %H:%M:%S %Y %Z""
   strptime 格式（C 区域）。

   以下为示例代码:

      >>> import ssl
      >>> timestamp = ssl.cert_time_to_seconds("Jan  5 09:34:43 2018 GMT")
      >>> timestamp  
      1515144883
      >>> from datetime import datetime
      >>> print(datetime.utcfromtimestamp(timestamp))  
      2018-01-05 09:34:43

   "notBefore" 或 "notAfter" 日期值必须使用 GMT (**RFC 5280**)。

   3.5 版更變: 将输入时间解读为 UTC 时间，基于输入字符串中指明的 'GMT'
   时区。 在之前使用的是本地时区。 返回一个整数（不带输入格式中秒的分
   数部分）

ssl.get_server_certificate(addr, ssl_version=PROTOCOL_TLS, ca_certs=None)

   带 SSL 保护的服务器的地址 "addr" 以 (*hostname*, *port-number*) 对
   的形式给出，获取服务器的证书，并将其以 PEM 编码字符串的形式返回。
   如果指定了 "ssl_version"，则使用该版本的 SSL 协议尝试连接服务器。
   如果指定了 "ca_certs"，它应当是一个包含根证书列表的文件，使用与
   "SSLContext.wrap_socket()" 中同名形参一致的格式。 该调用将尝试根据
   指定的根证书集来验证服务器证书，如果验证失败则该调用也将失败。

   3.3 版更變: 此函数现在是 IPv6 兼容的。-compatible.

   3.5 版更變: 默认的 *ssl_version* 从 "PROTOCOL_SSLv3" 改为
   "PROTOCOL_TLS" 以保证与现代服务器的最大兼容性。

ssl.DER_cert_to_PEM_cert(DER_cert_bytes)

   根据给定的 DER 编码字节块形式的证书，返回同一证书的 PEM 编码字符串
   版本。

ssl.PEM_cert_to_DER_cert(PEM_cert_string)

   根据给定的 ASCII PEM 字符串形式的证书，返回同一证书的 DER 编码字节
   序列。

ssl.get_default_verify_paths()

   返回包含 OpenSSL 的默认 cafile 和 capath 的路径的命名元组。 此路径
   与 "SSLContext.set_default_verify_paths()" 所使用的相同。 返回值是
   一个 *named tuple* "DefaultVerifyPaths":

   * "cafile" - 解析出的 cafile 路径或者如果文件不存在则为 "None",

   * "capath" - 解析出的 capath 路径或者如果目录不存在则为 "None",

   * "openssl_cafile_env" - 指向一个 cafile 的 OpenSSL 环境键,

   * "openssl_cafile" - 一个 cafile 的硬编码路径,

   * "openssl_capath_env" - 指向一个 capath 的 OpenSSL 环境键,

   * "openssl_capath" - 一个 capath 目录的硬编码路径

   可用性: LibreSSL 会忽略环境变量 "openssl_cafile_env" 和
   "openssl_capath_env"。

   3.4 版新加入.

ssl.enum_certificates(store_name)

   从 Windows 的系统证书库中检索证书。 *store_name* 可以是 "CA",
   "ROOT" 或 "MY" 中的一个。 Windows 也可能会提供额外的证书库。

   此函数返回一个包含 (cert_bytes, encoding_type, trust) 元组的列表。
   encoding_type 指明 cert_bytes 的编码格式。 它可以为 "x509_asn" 以表
   示 X.509 ASN.1 数据或是 "pkcs_7_asn" 以表示 PKCS#7 ASN.1 数据。
   trust 以 OIDS 集合的形式指明证书的目的，或者如果证书对于所有目的都
   可以信任则为 "True"。

   示例:

      >>> ssl.enum_certificates("CA")
      [(b'data...', 'x509_asn', {'1.3.6.1.5.5.7.3.1', '1.3.6.1.5.5.7.3.2'}),
       (b'data...', 'x509_asn', True)]

   可用性: Windows。

   3.4 版新加入.

ssl.enum_crls(store_name)

   Windows 的系统证书库中检索 CRL。 *store_name* 可以是 "CA", "ROOT"
   或 "MY" 中的一个。 Windows 也可能会提供额外的证书库。

   此函数返回一个包含 (cert_bytes, encoding_type, trust) 元组的列表。
   encoding_type 指明 cert_bytes 的编码格式。 它可以为 "x509_asn" 以表
   示 X.509 ASN.1 数据或是 "pkcs_7_asn" 以表示 PKCS#7 ASN.1 数据。

   可用性: Windows。

   3.4 版新加入.

ssl.wrap_socket(sock, keyfile=None, certfile=None, server_side=False, cert_reqs=CERT_NONE, ssl_version=PROTOCOL_TLS, ca_certs=None, do_handshake_on_connect=True, suppress_ragged_eofs=True, ciphers=None)

   接受一个 "socket.socket" 的实例 "sock"，并返回一个 "ssl.SSLSocket"
   的实例，该类型是 "socket.socket" 的子类型，它将下层的套接字包装在一
   个 SSL 上下文中。 "sock" 必须是一个 "SOCK_STREAM" 套接字；其他套接
   字类型不被支持。

   在内部，该函数会创建一个 "SSLContext"，其协议版本为 *ssl_version*
   且 "SSLContext.options" 设为 *cert_reqs*。 如果设置了 *keyfile*,
   *certfile*, *ca_certs* 或 *ciphers* 等形参，则参数值会被传给
   "SSLContext.load_cert_chain()",
   "SSLContext.load_verify_locations()" 以及
   "SSLContext.set_ciphers()"。

   参数 *server_side*, *do_handshake_on_connect* 和
   *suppress_ragged_eofs* 具有与 "SSLContext.wrap_socket()" 相同的含义
   。

   3.7 版後已棄用: 从 Python 3.2 和 2.7.9 开始，建议使用
   "SSLContext.wrap_socket()" 来代替 "wrap_socket()"。 模块级函数的功
   能受限并且将创建不安全的客户端套接字，不带服务器名称提示或主机名匹
   配。


常量
----

   所有常量现在都是 "enum.IntEnum" 或 "enum.IntFlag" 多项集的成员。

   3.6 版新加入.

ssl.CERT_NONE

   "SSLContext.verify_mode" 或 "wrap_socket()" 的 "cert_reqs" 形参可能
   的取值。 "PROTOCOL_TLS_CLIENT" 除外，这是默认的模式。 对于客户端套
   接字，几乎任何证书都是可接受的。 验证错误例如不受信任或过期的证书错
   误会被忽略并且不会中止 TLS/SSL 握手。

   在服务器模式下，不会从客户端请求任何证书，因此客户端不会发送任何用
   于客户端证书身份验证的证书。

   参见下文对于 Security considerations 的讨论。

ssl.CERT_OPTIONAL

   "SSLContext.verify_mode" 或 "wrap_socket()" 的 "cert_reqs" 形参可能
   的取值。 "CERT_OPTIONAL" 具有与 "CERT_REQUIRED" 相同的含义。 对于客
   户端套接字推荐改用 "CERT_REQUIRED"。

   在服务器模式下，客户端证书请求会被发送给客户端。 客户端可以忽略请求
   也可以发送一个证书以执行 TLS 客户端证书身份验证。 如果客户端选择发
   送证书，则将对其执行验证。 任何验证错误都将立即中止 TLS 握手。

   使用此设置要求将一组有效的 CA 证书传递给
   "SSLContext.load_verify_locations()" 或是作为 "wrap_socket()" 的
   "ca_certs" 形参值。

ssl.CERT_REQUIRED

   "SSLContext.verify_mode" 或 "wrap_socket()" 的 "cert_reqs" 形参可能
   的取值。 在此模式下，需要从套接字连接的另一端获取证书；如果未提供证
   书或验证失败则将引发 "SSLError"。 此模式 **不能** 在客户端模式下对
   证书进行验证，因为它不会匹配主机名。 "check_hostname" 也必须被启用
   以验证证书的真实性。 "PROTOCOL_TLS_CLIENT" 会使用 "CERT_REQUIRED"
   并默认启用 "check_hostname"。

   对于服务器套接字，此模式会提供强制性的 TLS 客户端证书验证。 客户端
   证书请求会被发送给客户端并且客户端必须提供有效且受信任的证书。

   使用此设置要求将一组有效的 CA 证书传递给
   "SSLContext.load_verify_locations()" 或是作为 "wrap_socket()" 的
   "ca_certs" 形参值。

class ssl.VerifyMode

   CERT_* 常量的 "enum.IntEnum" 多项集。

   3.6 版新加入.

ssl.VERIFY_DEFAULT

   "SSLContext.verify_flags" 可能的取值。 在此模式下，证书吊销列表（
   CRL）并不会被检查。 OpenSSL 默认不要求也不验证 CRL。

   3.4 版新加入.

ssl.VERIFY_CRL_CHECK_LEAF

   "SSLContext.verify_flags" 可能的取值。 在此模式下， 只会检查对等证
   书而不检查任何中间 CA 证书。 此模式要求提供由对等证书颁发者（其直接
   上级 CA）签名的有效 CRL。 如果未使用
   "SSLContext.load_verify_locations" 加载正确的 CRL，则验证将失败。

   3.4 版新加入.

ssl.VERIFY_CRL_CHECK_CHAIN

   "SSLContext.verify_flags" 可能的取值。 在此模式下，会检查对等证书链
   中所有证书的 CRL。

   3.4 版新加入.

ssl.VERIFY_X509_STRICT

   "SSLContext.verify_flags" 可能的取值，用于禁用已损坏 X.509 证书的绕
   过操作。

   3.4 版新加入.

ssl.VERIFY_X509_TRUSTED_FIRST

   "SSLContext.verify_flags" 可能的取值。 它指示 OpenSSL 在构建用于验
   证某个证书的信任链时首选受信任的证书。 此旗标将默认被启用。

   3.4.4 版新加入.

class ssl.VerifyFlags

   VERIFY_* 常量的 "enum.IntFlag" 多项集。

   3.6 版新加入.

ssl.PROTOCOL_TLS

   选择客户端和服务器均支持的最高协议版本。 此选项名称并不准确，实际上
   "SSL" 和 "TLS" 协议均可被选择。

   3.6 版新加入.

ssl.PROTOCOL_TLS_CLIENT

   像 "PROTOCOL_TLS" 一样地自动协商最高协议版本，但是只支持客户端
   "SSLSocket" 连接。 此协议默认会启用 "CERT_REQUIRED" 和
   "check_hostname"。

   3.6 版新加入.

ssl.PROTOCOL_TLS_SERVER

   像 "PROTOCOL_TLS" 一样地自动协商最高协议版本，但是只支持服务器
   "SSLSocket" 连接。

   3.6 版新加入.

ssl.PROTOCOL_SSLv23

   "PROTOCOL_TLS" 的别名。

   3.6 版後已棄用: 请改用 "PROTOCOL_TLS"。

ssl.PROTOCOL_SSLv2

   选择 SSL 版本 2 作为通道加密协议。

   如果 OpenSSL 编译时使用了 "OPENSSL_NO_SSL2" 旗标则此协议将不可用。

   警告:

     SSL 版本 2 并不安全。 极不建议使用它。

   3.6 版後已棄用: OpenSSL 已经移除了对 SSLv2 的支持。

ssl.PROTOCOL_SSLv3

   选择 SSL 版本 3 作为通道加密协议。

   如果 OpenSSL 编译时使用了 "OPENSSL_NO_SSLv3" 旗标则此协议将不可用。

   警告:

     SSL 版本 3 并不安全。 极不建议使用它。

   3.6 版後已棄用: OpenSSL 已经弃用了所有带有特定版本号的协议。 请改用
   默认协议 "PROTOCOL_TLS" 并附带 "OP_NO_SSLv3" 等旗标。

ssl.PROTOCOL_TLSv1

   选择 TLS 版本 1.0 作为通道加密协议。

   3.6 版後已棄用: OpenSSL 已经弃用了所有带有特定版本号的协议。 请改用
   默认协议 "PROTOCOL_TLS" 并附带 "OP_NO_SSLv3" 等旗标。

ssl.PROTOCOL_TLSv1_1

   选择 TLS 版本 1.1 作为通道加密协议。 仅适用于 openssl 版本 1.0.1+。

   3.4 版新加入.

   3.6 版後已棄用: OpenSSL 已经弃用了所有带有特定版本号的协议。 请改用
   默认协议 "PROTOCOL_TLS" 并附带 "OP_NO_SSLv3" 等旗标。

ssl.PROTOCOL_TLSv1_2

   选译 TLS 版本 1.2 作为通道加密协议。 这是最新的版本，也应是能提供最
   大保护的最佳选择，如果通信双方都支持它的话。 仅适用于 openssl 版本
   1.0.1+。

   3.4 版新加入.

   3.6 版後已棄用: OpenSSL 已经弃用了所有带有特定版本号的协议。 请改用
   默认协议 "PROTOCOL_TLS" 并附带 "OP_NO_SSLv3" 等旗标。

ssl.OP_ALL

   对存在于其他 SSL 实现中的各种缺陷启用绕过操作。 默认会设置此选项。
   没有必要设置与 OpenSSL 的 "SSL_OP_ALL" 常量同名的旗标。

   3.2 版新加入.

ssl.OP_NO_SSLv2

   阻止 SSLv2 连接。 此选项仅可与 "PROTOCOL_TLS" 结合使用。 它会阻止对
   等方选择 SSLv2 作为协议版本。

   3.2 版新加入.

   3.6 版後已棄用: SSLv2 已被弃用

ssl.OP_NO_SSLv3

   阻止 SSLv3 连接。 此选项仅可与 "PROTOCOL_TLS" 结合使用。 它会阻止对
   等方选择 SSLv3 作为协议版本。

   3.2 版新加入.

   3.6 版後已棄用: SSLv3 已被弃用

ssl.OP_NO_TLSv1

   阻止 TLSv1 连接。 此选项仅可与 "PROTOCOL_TLS" 结合使用。 它会阻止对
   等方选择 TLSv1 作为协议版本。

   3.2 版新加入.

   3.7 版後已棄用: 此选项自 OpenSSL 1.1.0 起已被弃用，请改用新的
   "SSLContext.minimum_version" 和 "SSLContext.maximum_version"。

ssl.OP_NO_TLSv1_1

   阻止 TLSv1.1 连接。 此选项仅可与 "PROTOCOL_TLS" 结合使用。 它会阻止
   对等方选择 TLSv1.1 作为协议版本。 仅适用于 openssl 版本 1.0.1+。

   3.4 版新加入.

   3.7 版後已棄用: 此选项自 OpenSSL 1.1.0 起已被弃用。

ssl.OP_NO_TLSv1_2

   阻止 TLSv1.2 连接。 此选项仅可与 "PROTOCOL_TLS" 结合使用。 它会阻止
   对等方选择 TLSv1.2 作为协议版本。 仅适用于 openssl 版本 1.0.1+。

   3.4 版新加入.

   3.7 版後已棄用: 此选项自 OpenSSL 1.1.0 起已被弃用。

ssl.OP_NO_TLSv1_3

   阻止 TLSv1.3 连接。 此选项仅可与 "PROTOCOL_TLS" 结合使用。 它会阻止
   对等方选择 TLSv1.3 作为协议版本。 TLS 1.3 适用于 OpenSSL 1.1.1 或更
   新的版本。 当 Python 编译是基于较旧版本的 OpenSSL 时，该旗标默认为
   *0*。

   3.7 版新加入.

   3.7 版後已棄用: 此选项自 OpenSSL 1.1.0 起已被弃用。 它被添加到
   2.7.15, 3.6.3 和 3.7.0 是为了向下兼容 OpenSSL 1.0.2。

ssl.OP_NO_RENEGOTIATION

   禁用所有 TLSv1.2 和更早版本的重协商操作。 不发送 HelloRequest 消息
   ，并忽略通过 ClientHello 发起的重协商请求。

   此选项仅适用于 OpenSSL 1.1.0h 及更新的版本。

   3.7 版新加入.

ssl.OP_CIPHER_SERVER_PREFERENCE

   使用服务器的密码顺序首选项，而不是客户端的首选项。 此选项在客户端套
   接字和 SSLv2 服务器套接字上无效。

   3.3 版新加入.

ssl.OP_SINGLE_DH_USE

   阻止对于单独的 SSL 会话重用相同的 DH 密钥。 这会提升前向保密性但需
   要更多的计算资源。 此选项仅适用于服务器套接字。

   3.3 版新加入.

ssl.OP_SINGLE_ECDH_USE

   阻止对于单独的 SSL 会话重用相同的 ECDH 密钥。 这会提升前向保密性但
   需要更多的计算资源。 此选项仅适用于服务器套接字。

   3.3 版新加入.

ssl.OP_ENABLE_MIDDLEBOX_COMPAT

   在 TLS 1.3 握手中发送虚拟更改密码规格（CCS）消息以使得 TLS 1.3 连接
   看起来更像是 TLS 1.2 连接。

   此选项仅适用于 OpenSSL 1.1.1 及更新的版本。

   3.8 版新加入.

ssl.OP_NO_COMPRESSION

   在 SSL 通道上禁用压缩。 这适用于应用协议支持自己的压缩方案的情况。

   此选项仅适用于 OpenSSL 1.0.0 及更新的版本。

   3.3 版新加入.

class ssl.Options

   OP_* 常量的 "enum.IntFlag" 多项集。

ssl.OP_NO_TICKET

   阻止客户端请求会话凭据。

   3.6 版新加入.

ssl.HAS_ALPN

   OpenSSL 库是否具有对 **RFC 7301** 中描述的 *应用层协议协商* TLS 扩
   展的内置支持。

   3.5 版新加入.

ssl.HAS_NEVER_CHECK_COMMON_NAME

   OpenSSL 库是否具有对不检测目标通用名称的内置支持且
   "SSLContext.hostname_checks_common_name" 为可写状态。

   3.7 版新加入.

ssl.HAS_ECDH

   OpenSSL 库是否具有对基于椭圆曲线的 Diffie-Hellman 密钥交换的内置支
   持。 此常量应当为真值，除非发布者明确地禁用了此功能。

   3.3 版新加入.

ssl.HAS_SNI

   OpenSSL 库是否具有对 *服务器名称提示* 扩展（在 **RFC 6066** 中定义
   ）的内置支持。

   3.2 版新加入.

ssl.HAS_NPN

   OpenSSL 库是否具有对 应用层协议协商 中描述的 *下一协议协商* 的内置
   支持。 当此常量为真值时，你可以使用
   "SSLContext.set_npn_protocols()" 方法来公告你想要支持的协议。

   3.3 版新加入.

ssl.HAS_SSLv2

   OpenSSL 库是否具有对 SSL 2.0 协议的内置支持。

   3.7 版新加入.

ssl.HAS_SSLv3

   OpenSSL 库是否具有对 SSL 3.0 协议的内置支持。

   3.7 版新加入.

ssl.HAS_TLSv1

   OpenSSL 库是否具有对 TLS 1.0 协议的内置支持。

   3.7 版新加入.

ssl.HAS_TLSv1_1

   OpenSSL 库是否具有对 TLS 1.1 协议的内置支持。

   3.7 版新加入.

ssl.HAS_TLSv1_2

   OpenSSL 库是否具有对 TLS 1.2 协议的内置支持。

   3.7 版新加入.

ssl.HAS_TLSv1_3

   OpenSSL 库是否具有对 TLS 1.3 协议的内置支持。

   3.7 版新加入.

ssl.CHANNEL_BINDING_TYPES

   受支持的 TLS 通道绑定类型组成的列表。 此列表中的字符串可被用作传给
   "SSLSocket.get_channel_binding()" 的参数。

   3.3 版新加入.

ssl.OPENSSL_VERSION

   解释器所加载的 OpenSSL 库的版本字符串:

      >>> ssl.OPENSSL_VERSION
      'OpenSSL 1.0.2k  26 Jan 2017'

   3.2 版新加入.

ssl.OPENSSL_VERSION_INFO

   代表 OpenSSL 库的版本信息的五个整数所组成的元组:

      >>> ssl.OPENSSL_VERSION_INFO
      (1, 0, 2, 11, 15)

   3.2 版新加入.

ssl.OPENSSL_VERSION_NUMBER

   OpenSSL 库的原始版本号，以单个整数表示:

      >>> ssl.OPENSSL_VERSION_NUMBER
      268443839
      >>> hex(ssl.OPENSSL_VERSION_NUMBER)
      '0x100020bf'

   3.2 版新加入.

ssl.ALERT_DESCRIPTION_HANDSHAKE_FAILURE
ssl.ALERT_DESCRIPTION_INTERNAL_ERROR
ALERT_DESCRIPTION_*

   来自 **RFC 5246** 等文档的警报描述。 IANA TLS Alert Registry 中包含
   了这个列表及对定义其含义的 RFC 引用。

   被用作 "SSLContext.set_servername_callback()" 中的回调函数的返回值
   。

   3.4 版新加入.

class ssl.AlertDescription

   ALERT_DESCRIPTION_* 常量的 "enum.IntEnum" 多项集。

   3.6 版新加入.

Purpose.SERVER_AUTH

   "create_default_context()" 和 "SSLContext.load_default_certs()" 的
   选项值。 这个值表明此上下文可以被用来验证 Web 服务器（因此，它将被
   用来创建客户端套接字）。

   3.4 版新加入.

Purpose.CLIENT_AUTH

   "create_default_context()" 和 "SSLContext.load_default_certs()" 的
   选项值。 这个值表明此上下文可以被用来验证 Web 客户端（因此，它将被
   用来创建服务器端套接字）。

   3.4 版新加入.

class ssl.SSLErrorNumber

   SSL_ERROR_* 常量的 "enum.IntEnum" 多项集。

   3.6 版新加入.

class ssl.TLSVersion

   "SSLContext.maximum_version" 和 "SSLContext.minimum_version" 中的
   SSL 和 TLS 版本的 "enum.IntEnum" 多项集。

   3.7 版新加入.

TLSVersion.MINIMUM_SUPPORTED

TLSVersion.MAXIMUM_SUPPORTED

   受支持的最低和最高 SSL 或 TLS 版本。 这些常量被称为魔术常量。 它们
   的值并不反映可用的最低和最高 TLS/SSL 版本。

TLSVersion.SSLv3

TLSVersion.TLSv1

TLSVersion.TLSv1_1

TLSVersion.TLSv1_2

TLSVersion.TLSv1_3

   SSL 3.0 至 TLS 1.3。


SSL 套接字
==========

class ssl.SSLSocket(socket.socket)

   SSL 套接字提供了 套接字对象 的下列方法:

   * "accept()"

   * "bind()"

   * "close()"

   * "connect()"

   * "detach()"

   * "fileno()"

   * "getpeername()", "getsockname()"

   * "getsockopt()", "setsockopt()"

   * "gettimeout()", "settimeout()", "setblocking()"

   * "listen()"

   * "makefile()"

   * "recv()", "recv_into()" (but passing a non-zero "flags" argument
     is not allowed)

   * "send()", "sendall()" (with the same limitation)

   * "sendfile()" (but "os.sendfile" will be used for plain-text
     sockets only, else "send()" will be used)

   * "shutdown()"

   但是，由于 SSL（和 TLS）协议在 TCP 之上具有自己的框架，因此 SSL 套
   接字抽象在某些方面可能与常规的 OS 层级套接字存在差异。 特别是要查看
   非阻塞型套接字说明。

   "SSLSocket" 的实例必须使用 "SSLContext.wrap_socket()" 方法来创建。

   3.5 版更變: 新增了 "sendfile()" 方法。

   3.5 版更變: "shutdown()" 不会在每次接收或发送字节数据后重置套接字超
   时。 现在套接字超时为关闭的最大总持续时间。

   3.6 版後已棄用: 直接创建 "SSLSocket" 实例的做法已被弃用，请使用
   "SSLContext.wrap_socket()" 来包装套接字。

   3.7 版更變: "SSLSocket" 的实例必须使用 "wrap_socket()" 来创建。 在
   较早的版本中，直接创建实例是可能的。 但这从未被记入文档或是被正式支
   持。

SSL 套接字还具有下列方法和属性:

SSLSocket.read(len=1024, buffer=None)

   从 SSL 套接字读取至多 *len* 个字节的数据并将结果作为 "bytes" 实例返
   回。 如果指定了 *buffer*，则改为读取到缓冲区，并返回所读取的字节数
   。

   如果套接字为 非阻塞型 则会引发 "SSLWantReadError" 或
   "SSLWantWriteError" 且读取将阻塞。

   由于在任何时候重新协商都是可能的，因此调用 "read()" 也可能导致写入
   操作。

   3.5 版更變: 套接字超时在每次接收或发送字节数据后不会再被重置。 现在
   套接字超时为读取至多 *len* 个字节数据的最大总持续时间。

   3.6 版後已棄用: 请使用 "recv()" 来代替 "read()"。

SSLSocket.write(buf)

   将 *buf* 写入到 SSL 套接字并返回所写入的字节数。 *buf* 参数必须为支
   持缓冲区接口的对象。

   如果套接字为 非阻塞型 则会引发 "SSLWantReadError" 或
   "SSLWantWriteError" 且读取将阻塞。

   由于在任何时候重新协商都是可能的，因此调用 "write()" 也可能导致读取
   操作。

   3.5 版更變: 套接字超时在每次接收或发送字节数据后不会再被重置。 现在
   套接字超时为写入 *buf* 的最大总持续时间。

   3.6 版後已棄用: 请使用 "send()" 来代替 "write()"。

備註:

  "read()" 和 "write()" 方法是读写未加密的应用级数据，并将其解密/加密
  为带加密的线路级数据的低层级方法。 这些方法需要有激活的 SSL 连接，即
  握手已完成而 "SSLSocket.unwrap()" 尚未被调用。通常你应当使用套接字
  API 方法例如 "recv()" 和 "send()" 来代替这些方法。

SSLSocket.do_handshake()

   执行 SSL 设置握手。

   3.4 版更變: 当套接字的 "context" 的 "check_hostname" 属性为真值时此
   握手方法还会执行 "match_hostname()"。

   3.5 版更變: 套接字超时在每次接收或发送字节数据时不会再被重置。 现在
   套接字超时为握手的最大总持续时间。

   3.7 版更變: 主机名或 IP 地址会在握手期间由 OpenSSL 进行匹配。 函数
   "match_hostname()" 将不再被使用。 在 OpenSSL 拒绝主机名和 IP 地址的
   情况下，握手将提前被中止并向对等方发送 TLS 警告消息。

SSLSocket.getpeercert(binary_form=False)

   如果连接另一端的对等方没有证书，则返回 "None"。 如果 SSL 握手还未完
   成，则会引发 "ValueError"。

   如果 "binary_form" 形参为 "False"，并且从对等方接收到了证书，此方法
   将返回一个 "dict" 实例。 如果证书未通过验证，则字典将为空。 如果证
   书通过验证，它将返回由多个密钥组成的字典，其中包括 "subject" (证书
   颁发给的主体) 和 "issuer" (颁发证书的主体)。 如果证书包含一个
   *Subject Alternative Name* 扩展的实例 (see **RFC 3280**)，则字典中
   还将有一个 "subjectAltName" 键。

   "subject" 和 "issuer" 字段都是包含在证书中相应字段的数据结构中给出
   的相对专有名称（RDN）序列的元组，每个 RDN 均为 name-value 对的序列
   。 这里是一个实际的示例:

      {'issuer': ((('countryName', 'IL'),),
                  (('organizationName', 'StartCom Ltd.'),),
                  (('organizationalUnitName',
                    'Secure Digital Certificate Signing'),),
                  (('commonName',
                    'StartCom Class 2 Primary Intermediate Server CA'),)),
       'notAfter': 'Nov 22 08:15:19 2013 GMT',
       'notBefore': 'Nov 21 03:09:52 2011 GMT',
       'serialNumber': '95F0',
       'subject': ((('description', '571208-SLe257oHY9fVQ07Z'),),
                   (('countryName', 'US'),),
                   (('stateOrProvinceName', 'California'),),
                   (('localityName', 'San Francisco'),),
                   (('organizationName', 'Electronic Frontier Foundation, Inc.'),),
                   (('commonName', '*.eff.org'),),
                   (('emailAddress', 'hostmaster@eff.org'),)),
       'subjectAltName': (('DNS', '*.eff.org'), ('DNS', 'eff.org')),
       'version': 3}

   備註:

     要验证特定服务的证书，你可以使用 "match_hostname()" 函数。

   如果 "binary_form" 形参为 "True"，并且提供了证书，此方法会将整个证
   书的 DER 编码形式作为字节序列返回，或者如果对等方未提供证书则返回
   "None"。 对等方是否提供证书取决于 SSL 套接字的角色:

   * 对于客户端 SSL 套接字，服务器将总是提供证书，无论是否需要进行验证
     ;

   * 对于服务器 SSL 套接字，客户端将仅在服务器要求时才提供证书；因此如
     果你使用了 "CERT_NONE" (而不是 "CERT_OPTIONAL" 或
     "CERT_REQUIRED") 则 "getpeercert()" 将返回 "None"。

   3.2 版更變: 返回的字典包括额外的条目例如 "issuer" 和 "notBefore"。

   3.4 版更變: 如果握手未完成则会引发 "ValueError"。 返回的字典包括额
   外的 X509v3 扩展条目例如 "crlDistributionPoints", "caIssuers" 和
   "OCSP" URI。

   3.9 版更變: IPv6 地址字符串不再附带末尾换行符。

SSLSocket.cipher()

   返回由三个值组成的元组，其中包含所使用的密码名称，定义其使用方式的
   SSL 协议版本，以及所使用的加密比特位数。 如果尚未建立连接，则返回
   "None"。

SSLSocket.shared_ciphers()

   返回在握手期间由客户端共享的密码列表。 所返回列表的每个条目都是由三
   个值组成的元组，其中包括密码名称，定义其使用方式的 SSL 协议版本，以
   及密码所使用的加密比特位数。 如果尚未建立连接或套接字为客户端套接字
   则 "shared_ciphers()" 将返回 "None"。

   3.5 版新加入.

SSLSocket.compression()

   以字符串形式返回所使用的压缩算法，或者如果连接没有使用压缩则返回
   "None"。

   如果高层级的协议支持自己的压缩机制，你可以使用 "OP_NO_COMPRESSION"
   来禁用 SSL 层级的压缩。

   3.3 版新加入.

SSLSocket.get_channel_binding(cb_type="tls-unique")

   为当前连接获取字节串形式的通道绑定数据。 如果尚未连接或握手尚未完成
   则返回 "None"。

   *cb_type* 形参允许选择需要的通道绑定类型。 有效的通道绑定类型在
   "CHANNEL_BINDING_TYPES" 列表中列出。 目前只支持由 **RFC 5929** 所定
   义的 'tls-unique' 通道绑定。 如果请求了一个不受支持的通道绑定类型则
   将引发 "ValueError"。

   3.3 版新加入.

SSLSocket.selected_alpn_protocol()

   返回在 TLS 握手期间所选择的协议。 如果
   "SSLContext.set_alpn_protocols()" 未被调用，如果另一方不支持 ALPN，
   如果此套接字不支持任何客户端所用的协议，或者如果握手尚未发生，则将
   返回 "None"。

   3.5 版新加入.

SSLSocket.selected_npn_protocol()

   返回在Return the higher-level protocol that was selected during the
   TLS/SSL 握手期间所选择的高层级协议。 如果
   "SSLContext.set_npn_protocols()" 未被调用，或者如果另一方不支持 NPN
   ，或者如果握手尚未发生，则将返回 "None"。

   3.3 版新加入.

SSLSocket.unwrap()

   执行 SSL 关闭握手，这会从下层的套接字中移除 TLS 层，并返回下层的套
   接字对象。 这可被用来通过一个连接将加密操作转为非加密。 返回的套接
   字应当总是被用于同连接另一方的进一步通信，而不是原始的套接字。

SSLSocket.verify_client_post_handshake()

   向一个 TLS 1.3 客户端请求握手后身份验证（PHA）。 只有在初始 TLS 握
   手之后且双方都启用了 PHA 的情况下才能为服务器端套接字的 TLS 1.3 连
   接启用 PHA，参见 "SSLContext.post_handshake_auth"。

   此方法不会立即执行证书交换。 服务器端会在下一次写入事件期间发送
   CertificateRequest 并期待客户端在下一次读取事件期间附带证书进行响应
   。

   如果有任何前置条件未被满足（例如非 TLS 1.3，PHA 未启用），则会引发
   "SSLError"。

   備註:

     仅在 OpenSSL 1.1.1 且 TLS 1.3 被启用时可用。 没有 TLS 1.3 支持，
     此方法将引发 "NotImplementedError"。

   3.8 版新加入.

SSLSocket.version()

   以字符串形式返回由连接协商确定的实际 SSL 协议版本，或者如果未建立安
   全连接则返回 "None"。 在撰写本文档时，可能的返回值包括 ""SSLv2"",
   ""SSLv3"", ""TLSv1"", ""TLSv1.1"" 和 ""TLSv1.2""。 最新的 OpenSSL
   版本可能会定义更多的返回值。

   3.5 版新加入.

SSLSocket.pending()

   返回在连接上等待被读取的已解密字节数。

SSLSocket.context

   此 SSL 套接字所联结的 "SSLContext" 对象。 如果 SSL 套接字是使用已弃
   用的 "wrap_socket()" 函数 (而非 "SSLContext.wrap_socket()") 创建的
   ，则这将是为此 SSL 套接字创建的自定义上下文对象。

   3.2 版新加入.

SSLSocket.server_side

   一个布尔值，对于服务器端套接字为 "True" 而对于客户端套接字则为
   "False"。

   3.2 版新加入.

SSLSocket.server_hostname

   服务器的主机名: "str" 类型，对于服务器端套接字或者如果构造器中未指
   定主机名则为 "None"。

   3.2 版新加入.

   3.7 版更變: 现在该属性将始终为 ASCII 文本。 当 "server_hostname" 为
   一个国际化域名（IDN）时，该属性现在会保存为 A 标签形式 (""xn
   --pythn-mua.org"") 而非 U 标签形式 (""pythön.org"")。

SSLSocket.session

   用于 SSL 连接的 "SSLSession"。 该会话将在执行 TLS 握手后对客户端和
   服务器端套接字可用。 对于客户端套接字该会话可以在调用
   "do_handshake()" 之前被设置以重用一个会话。

   3.6 版新加入.

SSLSocket.session_reused

   3.6 版新加入.


SSL 上下文
==========

3.2 版新加入.

SSL 上下文可保存各种比单独 SSL 连接寿命更长的数据，例如 SSL 配置选项，
证书和私钥等。 它还可为服务器端套接字管理缓存，以加快来自相同客户端的
重复连接。

class ssl.SSLContext(protocol=PROTOCOL_TLS)

   创建一个新的 SSL 上下文。 你可以传入 *protocol*，它必须为此模块中定
   义的 "PROTOCOL_*" 常量之一。 该形参指定要使用哪个 SSL 协议版本。 通
   常，服务器会选择一个特定的协议版本，而客户端必须适应服务器的选择。
   大多数版本都不能与其他版本互操作。 如果未指定，则默认值为
   "PROTOCOL_TLS"；它提供了与其他版本的最大兼容性。

   这个表显示了客户端（横向）的哪个版本能够连接服务器（纵向）的哪个版
   本。

      +--------------------------+--------------+--------------+---------------+-----------+-------------+-------------+
      | *客户端* / **服务器**    | **SSLv2**    | **SSLv3**    | **TLS** [3]   | **TLSv1** | **TLSv1.1** | **TLSv1.2** |
      +--------------------------+--------------+--------------+---------------+-----------+-------------+-------------+
      | *SSLv2*                  | 是           | 否           | 否 [1]        | 否        | 否          | 否          |
      +--------------------------+--------------+--------------+---------------+-----------+-------------+-------------+
      | *SSLv3*                  | 否           | 是           | 否 [2]        | 否        | 否          | 否          |
      +--------------------------+--------------+--------------+---------------+-----------+-------------+-------------+
      | *TLS* (*SSLv23*) [3]     | 否 [1]       | 否 [2]       | 是            | 是        | 是          | 是          |
      +--------------------------+--------------+--------------+---------------+-----------+-------------+-------------+
      | *TLSv1*                  | 否           | 否           | 是            | 是        | 否          | 否          |
      +--------------------------+--------------+--------------+---------------+-----------+-------------+-------------+
      | *TLSv1.1*                | 否           | 否           | 是            | 否        | 是          | 否          |
      +--------------------------+--------------+--------------+---------------+-----------+-------------+-------------+
      | *TLSv1.2*                | 否           | 否           | 是            | 否        | 否          | 是          |
      +--------------------------+--------------+--------------+---------------+-----------+-------------+-------------+

   -[ 脚注 ]-

   [1] "SSLContext" 默认设置 "OP_NO_SSLv2" 以禁用 SSLv2。

   [2] "SSLContext" 默认设置 "OP_NO_SSLv3" 以禁用 SSLv3。

   [3] TLS 1.3 协议在 OpenSSL >= 1.1.1 中设置 "PROTOCOL_TLS" 时可用。
       没有专门针对 TLS 1.3 的 PROTOCOL 常量。

   也參考: "create_default_context()" 让 "ssl" 为特定目标选择安全设置。

   3.6 版更變: 上下文会使用安全默认值来创建。 默认设置的选项有
   "OP_NO_COMPRESSION", "OP_CIPHER_SERVER_PREFERENCE",
   "OP_SINGLE_DH_USE", "OP_SINGLE_ECDH_USE", "OP_NO_SSLv2" (except for
   "PROTOCOL_SSLv2") 和 "OP_NO_SSLv3" (except for "PROTOCOL_SSLv3")。
   初始密码集列表只包含 "HIGH" 密码，不包含 "NULL" 密码和 "MD5" 密码
   ("PROTOCOL_SSLv2" 除外)。

"SSLContext" 对象具有以下方法和属性:

SSLContext.cert_store_stats()

   获取以字典表示的有关已加载的 X.509 证书数量，被标记为 CA 证书的
   X.509 证书数量以及证书吊销列表的统计信息。

   具有一个 CA 证书和一个其他证书的上下文示例:

      >>> context.cert_store_stats()
      {'crl': 0, 'x509_ca': 1, 'x509': 2}

   3.4 版新加入.

SSLContext.load_cert_chain(certfile, keyfile=None, password=None)

   加载一个私钥及对应的证书。 *certfile* 字符串必须为以 PEM 格式表示的
   单个文件路径，该文件中包含证书以及确立证书真实性所需的任意数量的 CA
   证书。 如果存在 *keyfile* 字符串，它必须指向一个包含私钥的文件。 否
   则私钥也将从 *certfile* 中提取。 请参阅 证书 中的讨论来了解有关如何
   将证书存储至 *certfile* 的更多信息。

   *password* 参数可以是一个函数，调用时将得到用于解密私钥的密码。 它
   在私钥被加密且需要密码时才会被调用。 它调用时将不带任何参数，并且应
   当返回一个字符串、字节串或字节数组。 如果返回值是一个字符串，在用它
   解密私钥之前它将以 UTF-8 进行编码。 或者也可以直接将字符串、字节串
   或字节数组值作为 *password* 参数提供。 如果私钥未被加密且不需要密码
   则它将被忽略。

   如果未指定 *password* 参数且需要一个密码，将会使用 OpenSSL 内置的密
   码提示机制来交互式地提示用户输入密码。

   如果私钥不能匹配证书则会引发 "SSLError"。

   3.3 版更變: 新增可选参数 *password*。

SSLContext.load_default_certs(purpose=Purpose.SERVER_AUTH)

   从默认位置加载一组默认的 "证书颁发机构" (CA) 证书。 在 Windows 上它
   将从 "CA" 和 "ROOT" 系统存储中加载 CA 证书。 在其他系统上它会调用
   "SSLContext.set_default_verify_paths()"。 将来该方法也可能会从其他
   位置加载 CA 证书。

   *purpose* 旗标指明要加载哪一类 CA 证书。 默认设置
   "Purpose.SERVER_AUTH" 加载被标记且被信任用于 TLS Web 服务器验证（客
   户端套接字）的证书。 "Purpose.CLIENT_AUTH" 则加载用于在服务器端进行
   客户端证书验证的 CA 证书。

   3.4 版新加入.

SSLContext.load_verify_locations(cafile=None, capath=None, cadata=None)

   当 "verify_mode" 不为 "CERT_NONE" 时加载一组用于验证其他对等方证书
   的 "证书颁发机构" (CA) 证书。 必须至少指定 *cafile* 或 *capath* 中
   的一个。

   此方法还可加载 PEM 或 DER 格式的证书吊销列表 (CRL)，为此必须正确配
   置 "SSLContext.verify_flags"。

   如果存在 *cafile* 字符串，它应为 PEM 格式的级联 CA 证书文件的路径。
   请参阅 证书 中的讨论来了解有关如何处理此文件中的证书的更多信息。

   如果存在 *capath* 字符串，它应为包含多个 PEM 格式的 CA 证书的目录的
   路径，并遵循 OpenSSL 专属布局。

   如果存在 *cadata* 对象，它应为一个或多个 PEM 编码的证书的 ASCII 字
   符串或者 DER 编码的证书的 *bytes-like object*。 与 *capath* 一样
   PEM 编码的证书之外的多余行会被忽略，但至少要有一个证书。

   3.4 版更變: 新增可选参数 *cadata*

SSLContext.get_ca_certs(binary_form=False)

   获取已离开法人 "证书颁发机构" (CA) 证书列表。 如果 "binary_form" 形
   参为 "False" 则每个列表条目都是一个类似于 "SSLSocket.getpeercert()"
   输出的字典。 在其他情况下此方法将返回一个 DER 编码的证书的列表。 返
   回的列表不包含来自 *capath* 的证书，除非 SSL 连接请求并加载了一个证
   书。

   備註:

     capath 目录中的证书不会被加载，除非它们已至少被使用过一次。

   3.4 版新加入.

SSLContext.get_ciphers()

   获取已启用密码的列表。 该列表将按密码的优先级排序。 参见
   "SSLContext.set_ciphers()"。

   示例:

      >>> ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
      >>> ctx.set_ciphers('ECDHE+AESGCM:!ECDSA')
      >>> ctx.get_ciphers()  # OpenSSL 1.0.x
      [{'alg_bits': 256,
        'description': 'ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH     Au=RSA  '
                       'Enc=AESGCM(256) Mac=AEAD',
        'id': 50380848,
        'name': 'ECDHE-RSA-AES256-GCM-SHA384',
        'protocol': 'TLSv1/SSLv3',
        'strength_bits': 256},
       {'alg_bits': 128,
        'description': 'ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH     Au=RSA  '
                       'Enc=AESGCM(128) Mac=AEAD',
        'id': 50380847,
        'name': 'ECDHE-RSA-AES128-GCM-SHA256',
        'protocol': 'TLSv1/SSLv3',
        'strength_bits': 128}]

   在 OpenSSL 1.1 及更新的版本中密码字典会包含额外的字段:

      >>> ctx.get_ciphers()  # OpenSSL 1.1+
      [{'aead': True,
        'alg_bits': 256,
        'auth': 'auth-rsa',
        'description': 'ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH     Au=RSA  '
                       'Enc=AESGCM(256) Mac=AEAD',
        'digest': None,
        'id': 50380848,
        'kea': 'kx-ecdhe',
        'name': 'ECDHE-RSA-AES256-GCM-SHA384',
        'protocol': 'TLSv1.2',
        'strength_bits': 256,
        'symmetric': 'aes-256-gcm'},
       {'aead': True,
        'alg_bits': 128,
        'auth': 'auth-rsa',
        'description': 'ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH     Au=RSA  '
                       'Enc=AESGCM(128) Mac=AEAD',
        'digest': None,
        'id': 50380847,
        'kea': 'kx-ecdhe',
        'name': 'ECDHE-RSA-AES128-GCM-SHA256',
        'protocol': 'TLSv1.2',
        'strength_bits': 128,
        'symmetric': 'aes-128-gcm'}]

   可用性: OpenSSL 1.0.2+。

   3.6 版新加入.

SSLContext.set_default_verify_paths()

   从构建 OpenSSL 库时定义的文件系统路径中加载一组默认的 "证书颁发机构
   " (CA) 证书。 不幸的是，没有一种简单的方式能知道此方法是否执行成功
   ：如果未找到任何证书也不会返回错误。 不过，当 OpenSSL 库是作为操作
   系统的一部分被提供时，它的配置应当是正确的。

SSLContext.set_ciphers(ciphers)

   为使用此上下文创建的套接字设置可用密码。 它应当为 OpenSSL 密码列表
   格式 的字符串。 如果没有可被选择的密码（由于编译时选项或其他配置禁
   止使用所指定的任何密码），则将引发 "SSLError"。

   備註:

     在连接后，SSL 套接字的 "SSLSocket.cipher()" 方法将给出当前所选择
     的密码。在默认情况下 OpenSSL 1.1.1 会启用 TLS 1.3 密码套件。 该套
     件不能通过 "set_ciphers()" 来禁用。

SSLContext.set_alpn_protocols(protocols)

   指定在 SSL/TLS 握手期间套接字应当通告的协议。 它应为由 ASCII 字符串
   组成的列表，例如 "['http/1.1', 'spdy/2']"，按首选顺序排列。 协议的
   选择将在握手期间发生，并依据 **RFC 7301** 来执行。 在握手成功后，
   "SSLSocket.selected_alpn_protocol()" 方法将返回已达成一致的协议。

   如果 "HAS_ALPN" 为 "False" 则此方法将引发 "NotImplementedError"。

   当双方都支持 ALPN 但不能就协议达成一致时 OpenSSL 1.1.0 至 1.1.0e 将
   中止并引发 "SSLError"。 1.1.0f+ 的行为类似于 1.0.2，
   "SSLSocket.selected_alpn_protocol()" 返回 None。

   3.5 版新加入.

SSLContext.set_npn_protocols(protocols)

   指定在Specify which protocols the socket should advertise during
   the SSL/TLS 握手期间套接字应当通告的协议。 它应为由字符串组成的列表
   ，例如 "['http/1.1', 'spdy/2']"，按首选顺序排列。 协议的选择将在握
   手期间发生，并将依据 应用层协议协商 来执行。 在握手成功后，
   "SSLSocket.selected_npn_protocol()" 方法将返回已达成一致的协议。

   如果 "HAS_NPN" 为 "False" 则此方法将引发 "NotImplementedError"。

   3.3 版新加入.

SSLContext.sni_callback

   注册一个回调函数，当 TLS 客户端指定了一个服务器名称提示时，该回调函
   数将在 SSL/TLS 服务器接收到 TLS Client Hello 握手消息后被调用。 服
   务器名称提示机制的定义见 **RFC 6066** section 3 - Server Name
   Indication。

   每个 "SSLContext" 只能设置一个回调。 如果 *sni_callback* 被设置为
   "None" 则会禁用回调。 对该函数的后续调用将禁用之前注册的回调。

   此回调函数将附带三个参数来调用；第一个参数是 "ssl.SSLSocket"，第二
   个参数是代表客户端准备与之通信的服务器的字符串 (或者如果 TLS Client
   Hello 不包含服务器名称则为 "None") 而第三个参数是原来的
   "SSLContext"。 服务器名称参数为文本形式。 对于国际化域名，服务器名
   称是一个 IDN A 标签 (""xn--pythn-mua.org"")。

   此回调的一个典型用法是将 "ssl.SSLSocket" 的 "SSLSocket.context" 属
   性修改为一个 "SSLContext" 类型的新对象，该对象代表与服务器相匹配的
   证书链。

   由于 TLS 连接处于早期协商阶段，因此仅能使用有限的方法和属性例如
   "SSLSocket.selected_alpn_protocol()" 和 "SSLSocket.context"。
   "SSLSocket.getpeercert()", "SSLSocket.getpeercert()",
   "SSLSocket.cipher()" 和 "SSLSocket.compress()" 方法要求 TLS 连接已
   经过 TLS Client Hello 因而将既不包含返回有意义的值，也不能安全地调
   用它们。

   *sni_callback* 函数必须返回 "None" 以允许 TLS 协商继续进行。 如果想
   要 TLS 失败，则可以返回常量 "ALERT_DESCRIPTION_*"。 其他返回值将导
   致 TLS 的致命错误 "ALERT_DESCRIPTION_INTERNAL_ERROR"。

   如果从 *sni_callback* 函数引发了异常，则 TLS 连接将终止并发出 TLS
   致命警告消息 "ALERT_DESCRIPTION_HANDSHAKE_FAILURE"。

   如果 OpenSSL library 库在构建时定义了 OPENSSL_NO_TLSEXT 则此方法将
   返回 "NotImplementedError"。

   3.7 版新加入.

SSLContext.set_servername_callback(server_name_callback)

   这是被保留用于向下兼容的旧式 API。 在可能的情况下，你应当改用
   "sni_callback"。 给出的 *server_name_callback* 类似于
   *sni_callback*，不同之处在于当服务器主机名是 IDN 编码的国际化域名时
   ，*server_name_callback* 会接收到一个已编码的 U 标签
   (""pythön.org"")。

   如果发生了服务器名称解码错误。 TLS 连接将终止并向客户端发出
   "ALERT_DESCRIPTION_INTERNAL_ERROR" 最严重 TLS 警告消息。

   3.4 版新加入.

SSLContext.load_dh_params(dhfile)

   加载密钥生成参数用于 Diffie-Hellman (DH) 密钥交换。 使用 DH 密钥交
   换能以消耗（服务器和客户端的）计算资源为代价提升前向保密性。
   *dhfile* 参数应当为指向一个包含 PEM 格式的 DH 形参的文件的路径。

   此设置不会应用于客户端套接字。 你还可以使用 "OP_SINGLE_DH_USE" 选项
   来进一步提升安全性。

   3.3 版新加入.

SSLContext.set_ecdh_curve(curve_name)

   为基于椭圆曲线的 Elliptic Curve-based Diffie-Hellman (ECDH) 密钥交
   换设置曲线名称。 ECDH 显著快于常规 DH 同时据信同样安全。
   *curve_name* 形参应为描述某个知名椭圆曲线的字符串，例如受到广泛支持
   的曲线 "prime256v1"。

   此设置不会应用于客户端套接字。 你还可以使用 "OP_SINGLE_ECDH_USE" 选
   项来进一步提升安全性。

   如果 "HAS_ECDH" 为 "False" 则此方法将不可用。

   3.3 版新加入.

   也參考:

     SSL/TLS 与完美的前向保密性
        Vincent Bernat。

SSLContext.wrap_socket(sock, server_side=False, do_handshake_on_connect=True, suppress_ragged_eofs=True, server_hostname=None, session=None)

   包装一个现有的 Python 套接字 *sock* 并返回一个
   "SSLContext.sslsocket_class" 的实例 (默认为 "SSLSocket")。 返回的
   SSL 套接字会绑定上下文、设置以及证书。 *sock* 必须是一个
   "SOCK_STREAM" 套接字；其他套接字类型不被支持。

   形参 "server_side" 是一个布尔值，它标明希望从该套接字获得服务器端行
   为还是客户端行为。

   对于客户端套接字，上下文的构造会延迟执行；如果下层的套接字尚未连接
   ，上下文的构造将在对套接字调用 "connect()" 之后执行。 对于服务器端
   套接字，如果套接字没有远端对等方，它会被视为一个监听套接字，并且服
   务器端 SSL 包装操作会在通过 "accept()" 方法所接受的客户端连接上自动
   执行。 此方法可能会引发 "SSLError"。

   在客户端连接上，可选形参 *server_hostname* 指定所要连接的服务的主机
   名。 这允许单个服务器托管具有单独证书的多个基于 SSL 的服务，很类似
   于 HTTP 虚拟主机。 如果 *server_side* 为真值则指定
   *server_hostname* 将引发 "ValueError"。

   形参 "do_handshake_on_connect" 指明是否要在调用 "socket.connect()"
   之后自动执行 SSL 握手，还是要通过发起调用
   "SSLSocket.do_handshake()" 方法让应用程序显式地调用它。 显式地调用
   "SSLSocket.do_handshake()" 可给予程序对握手中所涉及的套接字 I/O 阻
   塞行为的控制。

   形参 "suppress_ragged_eofs" 指明 "SSLSocket.recv()" 方法应当如何从
   连接的另一端发送非预期的 EOF 信号。 如果指定为 "True" (默认值)，它
   将返回正常的 EOF (空字节串对象) 来响应从下层套接字引发的非预期的
   EOF 错误；如果指定为 "False"，它将向调用方引发异常。

   *session*，参见 "session"。

   3.5 版更變: 总是允许传送 server_hostname，即使 OpenSSL 没有 SNI。

   3.6 版更變: 增加了 *session* 参数。

   3.7 版更變: 此方法返回 "SSLContext.sslsocket_class" 的实例而非硬编
   码的 "SSLSocket"。

SSLContext.sslsocket_class

   "SSLContext.wrap_socket()" 的返回类型，默认为 "SSLSocket"。 该属性
   可以在类实例上被重载以便返回自定义的 "SSLSocket" 的子类。

   3.7 版新加入.

SSLContext.wrap_bio(incoming, outgoing, server_side=False, server_hostname=None, session=None)

   包装 BIO 对象 *incoming* 和 *outgoing* 并返回一个
   "SSLContext.sslobject_class" (默认为 "SSLObject") 的实例。 SSL 例程
   将从 BIO 中读取输入数据并将数据写入到 outgoing BIO。

   *server_side*, *server_hostname* 和 *session* 形参具有与
   "SSLContext.wrap_socket()" 中相同的含义。

   3.6 版更變: 增加了 *session* 参数。

   3.7 版更變: 此方法返回 "SSLContext.sslobject_class" 的实例则非硬编
   码的 "SSLObject"。

SSLContext.sslobject_class

   "SSLContext.wrap_bio()" 的返回类型，默认为 "SSLObject"。 该属性可以
   在类实例上被重载以便返回自定义的 "SSLObject" 的子类。

   3.7 版新加入.

SSLContext.session_stats()

   获取由此上下文所创建或管理的 SSL 会话的相关统计信息。 返回将每个 信
   息片 的名称映射到其数字值的字典。 例如，以下是自上下文被创建以来会
   话缓存中命中和未命中的总数:

      >>> stats = context.session_stats()
      >>> stats['hits'], stats['misses']
      (0, 0)

SSLContext.check_hostname

   是否要将对等方证书的主机名与 "SSLSocket.do_handshake()" 中的
   "match_hostname()" 进行匹配。 上下文的 "verify_mode" 必须被设为
   "CERT_OPTIONAL" 或 "CERT_REQUIRED"，并且你必须将 *server_hostname*
   传给 "wrap_socket()" 以便匹配主机名。 启用主机名检查会自动将 sets
   "verify_mode" 从 "CERT_NONE" 设置为 "CERT_REQUIRED"。 只要启用了主
   机名检查就不能将其设置回 "CERT_NONE"。 "PROTOCOL_TLS_CLIENT" 协议默
   认启用主机名检查。 对于其他协议，则必须显式地启用主机名检查。

   示例:

      import socket, ssl

      context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
      context.verify_mode = ssl.CERT_REQUIRED
      context.check_hostname = True
      context.load_default_certs()

      s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
      ssl_sock = context.wrap_socket(s, server_hostname='www.verisign.com')
      ssl_sock.connect(('www.verisign.com', 443))

   3.4 版新加入.

   3.7 版更變: 现在当主机名检查被启用且 "verify_mode" 为 "CERT_NONE"
   时 "verify_mode" 会自动更改为 "CERT_REQUIRED"。 在之前版本中同样的
   操作将失败并引发 "ValueError"。

   備註:

     此特性要求 OpenSSL 0.9.8f 或更新的版本。

SSLContext.keylog_filename

   每当生成或接收到密钥时，将 TLS 密钥写入到一个密钥日志文件。 密钥日
   志文件的设计仅适用于调试目的。 文件的格式由 NSS 指明并为许多流量分
   析工具例如 Wireshark 所使用。 日志文件会以追加模式打开。 写入操作会
   在线程之间同步，但不会在进程之间同步。

   3.8 版新加入.

   備註:

     此特性要求 OpenSSL 1.1.1 或更新的版本。

SSLContext.maximum_version

   一个代表所支持的最高 TLS 版本的 "TLSVersion" 枚举成员。 该值默认为
   "TLSVersion.MAXIMUM_SUPPORTED"。 这个属性对于 "PROTOCOL_TLS",
   "PROTOCOL_TLS_CLIENT" 和 "PROTOCOL_TLS_SERVER" 以外的其他协议来说都
   是只读的。

   "maximum_version", "minimum_version" 和 "SSLContext.options" 等属性
   都会影响上下文所支持的 SSL 和 TLS 版本。 这个实现不会阻止无效的组合
   。 例如一个 "options" 为 "OP_NO_TLSv1_2" 而 "maximum_version" 设为
   "TLSVersion.TLSv1_2" 的上下文将无法建立 TLS 1.2 连接。

   備註:

     除非 ssl 模块使用 OpenSSL 1.1.0g 或更新的版本编译否则这个属性将不
     可用。

   3.7 版新加入.

SSLContext.minimum_version

   与 "SSLContext.maximum_version" 类似，区别在于它是所支持的最低版本
   或为 "TLSVersion.MINIMUM_SUPPORTED"。

   備註:

     除非 ssl 模块使用 OpenSSL 1.1.0g 或更新的版本编译否则这个属性将不
     可用。

   3.7 版新加入.

SSLContext.num_tickets

   控制 "TLS_PROTOCOL_SERVER" 上下文的 TLS 1.3  会话凭据数量。 这个设
   置不会影响 TLS 1.0 到 1.2 连接。

   備註:

     除非 ssl 模块使用 OpenSSL 1.1.1 或更新的版本编译否则这个属性将不
     可用。

   3.8 版新加入.

SSLContext.options

   一个代表此上下文中所启用的 SSL 选项集的整数。 默认值为 "OP_ALL"，但
   你也可以通过在选项间进行 OR 运算来指定其他选项例如 "OP_NO_SSLv2"。

   備註:

     对于 0.9.8m 之前的 OpenSSL 版本，只能设置选项，而不能清除它们。
     尝试（通过重置相应比特位）清除选项将会引发 "ValueError"。

   3.6 版更變: "SSLContext.options" 返回 "Options" 旗标:

   >>> ssl.create_default_context().options  
   <Options.OP_ALL|OP_NO_SSLv3|OP_NO_SSLv2|OP_NO_COMPRESSION: 2197947391>

SSLContext.post_handshake_auth

   启用 TLS 1.3 握手后客户端身份验证。 握手后验证默认是被禁用的，服务
   器只能在初始握手期间请求 TLS 客户端证书。 当启用时，服务器可以在握
   手之后的任何时候请求 TLS 客户端证书。

   当在客户端套接字上启用时，客户端会向服务器发信号说明它支持握手后身
   份验证。

   当在服务器端套接字上启用时，"SSLContext.verify_mode" 也必须被设为
   "CERT_OPTIONAL" 或 "CERT_REQUIRED"。 实际的客户端证书交换会被延迟直
   至 "SSLSocket.verify_client_post_handshake()" 被调用并执行了一些
   I/O 操作后再进行。

   備註:

     仅在 OpenSSL 1.1.1 且 TLS 1.3 被启用时可用。 如果没有 TLS 1.3 支
     持，该属性值将为 None 且不可被更改

   3.8 版新加入.

SSLContext.protocol

   构造上下文时所选择的协议版本。 这个属性是只读的。

SSLContext.hostname_checks_common_name

   在没有目标替代名称扩展的情况下 "check_hostname" 是否要回退为验证证
   书的通用名称（默认为真值）。

   備註:

     仅在 OpenSSL 1.1.0 或更新的版本上可写。

   3.7 版新加入.

SSLContext.verify_flags

   证书验证操作的旗标。 你可以通过对 "VERIFY_CRL_CHECK_LEAF" 等值执行
   OR 运算来设置组合旗标。 在默认情况下 OpenSSL 不会要求也不会验证证书
   吊销列表（CRL）。 仅在 openssl 版本 0.9.8+ 上可用。

   3.4 版新加入.

   3.6 版更變: "SSLContext.verify_flags" 返回 "VerifyFlags" 旗标:

   >>> ssl.create_default_context().verify_flags  
   <VerifyFlags.VERIFY_X509_TRUSTED_FIRST: 32768>

SSLContext.verify_mode

   是否要尝试验证其他对等方的证书以及如果验证失败应采取何种行为。 该属
   性值必须为 "CERT_NONE", "CERT_OPTIONAL" 或 "CERT_REQUIRED" 之一。

   3.6 版更變: "SSLContext.verify_mode" 返回 "VerifyMode" 枚举:

   >>> ssl.create_default_context().verify_mode
   <VerifyMode.CERT_REQUIRED: 2>


证书
====

Certificates in general are part of a public-key / private-key system.
In this system, each *principal*, (which may be a machine, or a
person, or an organization) is assigned a unique two-part encryption
key.  One part of the key is public, and is called the *public key*;
the other part is kept secret, and is called the *private key*.  The
two parts are related, in that if you encrypt a message with one of
the parts, you can decrypt it with the other part, and **only** with
the other part.

A certificate contains information about two principals.  It contains
the name of a *subject*, and the subject's public key.  It also
contains a statement by a second principal, the *issuer*, that the
subject is who they claim to be, and that this is indeed the subject's
public key.  The issuer's statement is signed with the issuer's
private key, which only the issuer knows.  However, anyone can verify
the issuer's statement by finding the issuer's public key, decrypting
the statement with it, and comparing it to the other information in
the certificate. The certificate also contains information about the
time period over which it is valid.  This is expressed as two fields,
called "notBefore" and "notAfter".

In the Python use of certificates, a client or server can use a
certificate to prove who they are.  The other side of a network
connection can also be required to produce a certificate, and that
certificate can be validated to the satisfaction of the client or
server that requires such validation.  The connection attempt can be
set to raise an exception if the validation fails. Validation is done
automatically, by the underlying OpenSSL framework; the application
need not concern itself with its mechanics.  But the application does
usually need to provide sets of certificates to allow this process to
take place.

Python uses files to contain certificates.  They should be formatted
as "PEM" (see **RFC 1422**), which is a base-64 encoded form wrapped
with a header line and a footer line:

   -----BEGIN CERTIFICATE-----
   ... (certificate in base64 PEM encoding) ...
   -----END CERTIFICATE-----


Certificate chains
------------------

The Python files which contain certificates can contain a sequence of
certificates, sometimes called a *certificate chain*.  This chain
should start with the specific certificate for the principal who "is"
the client or server, and then the certificate for the issuer of that
certificate, and then the certificate for the issuer of *that*
certificate, and so on up the chain till you get to a certificate
which is *self-signed*, that is, a certificate which has the same
subject and issuer, sometimes called a *root certificate*.  The
certificates should just be concatenated together in the certificate
file.  For example, suppose we had a three certificate chain, from our
server certificate to the certificate of the certification authority
that signed our server certificate, to the root certificate of the
agency which issued the certification authority's certificate:

   -----BEGIN CERTIFICATE-----
   ... (certificate for your server)...
   -----END CERTIFICATE-----
   -----BEGIN CERTIFICATE-----
   ... (the certificate for the CA)...
   -----END CERTIFICATE-----
   -----BEGIN CERTIFICATE-----
   ... (the root certificate for the CA's issuer)...
   -----END CERTIFICATE-----


CA certificates
---------------

If you are going to require validation of the other side of the
connection's certificate, you need to provide a "CA certs" file,
filled with the certificate chains for each issuer you are willing to
trust.  Again, this file just contains these chains concatenated
together.  For validation, Python will use the first chain it finds in
the file which matches.  The platform's certificates file can be used
by calling "SSLContext.load_default_certs()", this is done
automatically with "create_default_context()".


Combined key and certificate
----------------------------

Often the private key is stored in the same file as the certificate;
in this case, only the "certfile" parameter to
"SSLContext.load_cert_chain()" and "wrap_socket()" needs to be passed.
If the private key is stored with the certificate, it should come
before the first certificate in the certificate chain:

   -----BEGIN RSA PRIVATE KEY-----
   ... (private key in base64 encoding) ...
   -----END RSA PRIVATE KEY-----
   -----BEGIN CERTIFICATE-----
   ... (certificate in base64 PEM encoding) ...
   -----END CERTIFICATE-----


Self-signed certificates
------------------------

If you are going to create a server that provides SSL-encrypted
connection services, you will need to acquire a certificate for that
service.  There are many ways of acquiring appropriate certificates,
such as buying one from a certification authority.  Another common
practice is to generate a self-signed certificate.  The simplest way
to do this is with the OpenSSL package, using something like the
following:

   % openssl req -new -x509 -days 365 -nodes -out cert.pem -keyout cert.pem
   Generating a 1024 bit RSA private key
   .......++++++
   .............................++++++
   writing new private key to 'cert.pem'
   -----
   You are about to be asked to enter information that will be incorporated
   into your certificate request.
   What you are about to enter is what is called a Distinguished Name or a DN.
   There are quite a few fields but you can leave some blank
   For some fields there will be a default value,
   If you enter '.', the field will be left blank.
   -----
   Country Name (2 letter code) [AU]:US
   State or Province Name (full name) [Some-State]:MyState
   Locality Name (eg, city) []:Some City
   Organization Name (eg, company) [Internet Widgits Pty Ltd]:My Organization, Inc.
   Organizational Unit Name (eg, section) []:My Group
   Common Name (eg, YOUR name) []:myserver.mygroup.myorganization.com
   Email Address []:ops@myserver.mygroup.myorganization.com
   %

The disadvantage of a self-signed certificate is that it is its own
root certificate, and no one else will have it in their cache of known
(and trusted) root certificates.


示例
====


Testing for SSL support
-----------------------

To test for the presence of SSL support in a Python installation, user
code should use the following idiom:

   try:
       import ssl
   except ImportError:
       pass
   else:
       ...  # do something that requires SSL support


Client-side operation
---------------------

This example creates a SSL context with the recommended security
settings for client sockets, including automatic certificate
verification:

   >>> context = ssl.create_default_context()

If you prefer to tune security settings yourself, you might create a
context from scratch (but beware that you might not get the settings
right):

   >>> context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
   >>> context.load_verify_locations("/etc/ssl/certs/ca-bundle.crt")

(this snippet assumes your operating system places a bundle of all CA
certificates in "/etc/ssl/certs/ca-bundle.crt"; if not, you'll get an
error and have to adjust the location)

The "PROTOCOL_TLS_CLIENT" protocol configures the context for cert
validation and hostname verification. "verify_mode" is set to
"CERT_REQUIRED" and "check_hostname" is set to "True". All other
protocols create SSL contexts with insecure defaults.

When you use the context to connect to a server, "CERT_REQUIRED" and
"check_hostname" validate the server certificate: it ensures that the
server certificate was signed with one of the CA certificates, checks
the signature for correctness, and verifies other properties like
validity and identity of the hostname:

   >>> conn = context.wrap_socket(socket.socket(socket.AF_INET),
   ...                            server_hostname="www.python.org")
   >>> conn.connect(("www.python.org", 443))

You may then fetch the certificate:

   >>> cert = conn.getpeercert()

Visual inspection shows that the certificate does identify the desired
service (that is, the HTTPS host "www.python.org"):

   >>> pprint.pprint(cert)
   {'OCSP': ('http://ocsp.digicert.com',),
    'caIssuers': ('http://cacerts.digicert.com/DigiCertSHA2ExtendedValidationServerCA.crt',),
    'crlDistributionPoints': ('http://crl3.digicert.com/sha2-ev-server-g1.crl',
                              'http://crl4.digicert.com/sha2-ev-server-g1.crl'),
    'issuer': ((('countryName', 'US'),),
               (('organizationName', 'DigiCert Inc'),),
               (('organizationalUnitName', 'www.digicert.com'),),
               (('commonName', 'DigiCert SHA2 Extended Validation Server CA'),)),
    'notAfter': 'Sep  9 12:00:00 2016 GMT',
    'notBefore': 'Sep  5 00:00:00 2014 GMT',
    'serialNumber': '01BB6F00122B177F36CAB49CEA8B6B26',
    'subject': ((('businessCategory', 'Private Organization'),),
                (('1.3.6.1.4.1.311.60.2.1.3', 'US'),),
                (('1.3.6.1.4.1.311.60.2.1.2', 'Delaware'),),
                (('serialNumber', '3359300'),),
                (('streetAddress', '16 Allen Rd'),),
                (('postalCode', '03894-4801'),),
                (('countryName', 'US'),),
                (('stateOrProvinceName', 'NH'),),
                (('localityName', 'Wolfeboro'),),
                (('organizationName', 'Python Software Foundation'),),
                (('commonName', 'www.python.org'),)),
    'subjectAltName': (('DNS', 'www.python.org'),
                       ('DNS', 'python.org'),
                       ('DNS', 'pypi.org'),
                       ('DNS', 'docs.python.org'),
                       ('DNS', 'testpypi.org'),
                       ('DNS', 'bugs.python.org'),
                       ('DNS', 'wiki.python.org'),
                       ('DNS', 'hg.python.org'),
                       ('DNS', 'mail.python.org'),
                       ('DNS', 'packaging.python.org'),
                       ('DNS', 'pythonhosted.org'),
                       ('DNS', 'www.pythonhosted.org'),
                       ('DNS', 'test.pythonhosted.org'),
                       ('DNS', 'us.pycon.org'),
                       ('DNS', 'id.python.org')),
    'version': 3}

Now the SSL channel is established and the certificate verified, you
can proceed to talk with the server:

   >>> conn.sendall(b"HEAD / HTTP/1.0\r\nHost: linuxfr.org\r\n\r\n")
   >>> pprint.pprint(conn.recv(1024).split(b"\r\n"))
   [b'HTTP/1.1 200 OK',
    b'Date: Sat, 18 Oct 2014 18:27:20 GMT',
    b'Server: nginx',
    b'Content-Type: text/html; charset=utf-8',
    b'X-Frame-Options: SAMEORIGIN',
    b'Content-Length: 45679',
    b'Accept-Ranges: bytes',
    b'Via: 1.1 varnish',
    b'Age: 2188',
    b'X-Served-By: cache-lcy1134-LCY',
    b'X-Cache: HIT',
    b'X-Cache-Hits: 11',
    b'Vary: Cookie',
    b'Strict-Transport-Security: max-age=63072000; includeSubDomains',
    b'Connection: close',
    b'',
    b'']

参见下文对于 Security considerations 的讨论。


Server-side operation
---------------------

For server operation, typically you'll need to have a server
certificate, and private key, each in a file.  You'll first create a
context holding the key and the certificate, so that clients can check
your authenticity.  Then you'll open a socket, bind it to a port, call
"listen()" on it, and start waiting for clients to connect:

   import socket, ssl

   context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
   context.load_cert_chain(certfile="mycertfile", keyfile="mykeyfile")

   bindsocket = socket.socket()
   bindsocket.bind(('myaddr.mydomain.com', 10023))
   bindsocket.listen(5)

When a client connects, you'll call "accept()" on the socket to get
the new socket from the other end, and use the context's
"SSLContext.wrap_socket()" method to create a server-side SSL socket
for the connection:

   while True:
       newsocket, fromaddr = bindsocket.accept()
       connstream = context.wrap_socket(newsocket, server_side=True)
       try:
           deal_with_client(connstream)
       finally:
           connstream.shutdown(socket.SHUT_RDWR)
           connstream.close()

Then you'll read data from the "connstream" and do something with it
till you are finished with the client (or the client is finished with
you):

   def deal_with_client(connstream):
       data = connstream.recv(1024)
       # empty data means the client is finished with us
       while data:
           if not do_something(connstream, data):
               # we'll assume do_something returns False
               # when we're finished with client
               break
           data = connstream.recv(1024)
       # finished with client

And go back to listening for new client connections (of course, a real
server would probably handle each client connection in a separate
thread, or put the sockets in non-blocking mode and use an event
loop).


Notes on non-blocking sockets
=============================

SSL sockets behave slightly different than regular sockets in non-
blocking mode. When working with non-blocking sockets, there are thus
several things you need to be aware of:

* Most "SSLSocket" methods will raise either "SSLWantWriteError" or
  "SSLWantReadError" instead of "BlockingIOError" if an I/O operation
  would block. "SSLWantReadError" will be raised if a read operation
  on the underlying socket is necessary, and "SSLWantWriteError" for a
  write operation on the underlying socket. Note that attempts to
  *write* to an SSL socket may require *reading* from the underlying
  socket first, and attempts to *read* from the SSL socket may require
  a prior *write* to the underlying socket.

  3.5 版更變: In earlier Python versions, the "SSLSocket.send()"
  method returned zero instead of raising "SSLWantWriteError" or
  "SSLWantReadError".

* Calling "select()" tells you that the OS-level socket can be read
  from (or written to), but it does not imply that there is sufficient
  data at the upper SSL layer.  For example, only part of an SSL frame
  might have arrived.  Therefore, you must be ready to handle
  "SSLSocket.recv()" and "SSLSocket.send()" failures, and retry after
  another call to "select()".

* Conversely, since the SSL layer has its own framing, a SSL socket
  may still have data available for reading without "select()" being
  aware of it.  Therefore, you should first call "SSLSocket.recv()" to
  drain any potentially available data, and then only block on a
  "select()" call if still necessary.

  (of course, similar provisions apply when using other primitives
  such as "poll()", or those in the "selectors" module)

* The SSL handshake itself will be non-blocking: the
  "SSLSocket.do_handshake()" method has to be retried until it returns
  successfully.  Here is a synopsis using "select()" to wait for the
  socket's readiness:

     while True:
         try:
             sock.do_handshake()
             break
         except ssl.SSLWantReadError:
             select.select([sock], [], [])
         except ssl.SSLWantWriteError:
             select.select([], [sock], [])

也參考:

  The "asyncio" module supports non-blocking SSL sockets and provides
  a higher level API. It polls for events using the "selectors" module
  and handles "SSLWantWriteError", "SSLWantReadError" and
  "BlockingIOError" exceptions. It runs the SSL handshake
  asynchronously as well.


Memory BIO Support
==================

3.5 版新加入.

Ever since the SSL module was introduced in Python 2.6, the
"SSLSocket" class has provided two related but distinct areas of
functionality:

* SSL protocol handling

* Network IO

The network IO API is identical to that provided by "socket.socket",
from which "SSLSocket" also inherits. This allows an SSL socket to be
used as a drop-in replacement for a regular socket, making it very
easy to add SSL support to an existing application.

Combining SSL protocol handling and network IO usually works well, but
there are some cases where it doesn't. An example is async IO
frameworks that want to use a different IO multiplexing model than the
"select/poll on a file descriptor" (readiness based) model that is
assumed by "socket.socket" and by the internal OpenSSL socket IO
routines. This is mostly relevant for platforms like Windows where
this model is not efficient. For this purpose, a reduced scope variant
of "SSLSocket" called "SSLObject" is provided.

class ssl.SSLObject

   A reduced-scope variant of "SSLSocket" representing an SSL protocol
   instance that does not contain any network IO methods. This class
   is typically used by framework authors that want to implement
   asynchronous IO for SSL through memory buffers.

   This class implements an interface on top of a low-level SSL object
   as implemented by OpenSSL. This object captures the state of an SSL
   connection but does not provide any network IO itself. IO needs to
   be performed through separate "BIO" objects which are OpenSSL's IO
   abstraction layer.

   This class has no public constructor.  An "SSLObject" instance must
   be created using the "wrap_bio()" method. This method will create
   the "SSLObject" instance and bind it to a pair of BIOs. The
   *incoming* BIO is used to pass data from Python to the SSL protocol
   instance, while the *outgoing* BIO is used to pass data the other
   way around.

   可以使用以下方法：

   * "context"

   * "server_side"

   * "server_hostname"

   * "session"

   * "session_reused"

   * "read()"

   * "write()"

   * "getpeercert()"

   * "selected_alpn_protocol()"

   * "selected_npn_protocol()"

   * "cipher()"

   * "shared_ciphers()"

   * "compression()"

   * "pending()"

   * "do_handshake()"

   * "verify_client_post_handshake()"

   * "unwrap()"

   * "get_channel_binding()"

   * "version()"

   When compared to "SSLSocket", this object lacks the following
   features:

   * Any form of network IO; "recv()" and "send()" read and write only
     to the underlying "MemoryBIO" buffers.

   * There is no *do_handshake_on_connect* machinery. You must always
     manually call "do_handshake()" to start the handshake.

   * There is no handling of *suppress_ragged_eofs*. All end-of-file
     conditions that are in violation of the protocol are reported via
     the "SSLEOFError" exception.

   * The method "unwrap()" call does not return anything, unlike for
     an SSL socket where it returns the underlying socket.

   * The *server_name_callback* callback passed to
     "SSLContext.set_servername_callback()" will get an "SSLObject"
     instance instead of a "SSLSocket" instance as its first
     parameter.

   Some notes related to the use of "SSLObject":

   * All IO on an "SSLObject" is non-blocking. This means that for
     example "read()" will raise an "SSLWantReadError" if it needs
     more data than the incoming BIO has available.

   * There is no module-level "wrap_bio()" call like there is for
     "wrap_socket()". An "SSLObject" is always created via an
     "SSLContext".

   3.7 版更變: "SSLObject" instances must to created with
   "wrap_bio()". In earlier versions, it was possible to create
   instances directly. This was never documented or officially
   supported.

An SSLObject communicates with the outside world using memory buffers.
The class "MemoryBIO" provides a memory buffer that can be used for
this purpose.  It wraps an OpenSSL memory BIO (Basic IO) object:

class ssl.MemoryBIO

   A memory buffer that can be used to pass data between Python and an
   SSL protocol instance.

   pending

      Return the number of bytes currently in the memory buffer.

   eof

      A boolean indicating whether the memory BIO is current at the
      end-of-file position.

   read(n=-1)

      Read up to *n* bytes from the memory buffer. If *n* is not
      specified or negative, all bytes are returned.

   write(buf)

      Write the bytes from *buf* to the memory BIO. The *buf* argument
      must be an object supporting the buffer protocol.

      The return value is the number of bytes written, which is always
      equal to the length of *buf*.

   write_eof()

      Write an EOF marker to the memory BIO. After this method has
      been called, it is illegal to call "write()". The attribute
      "eof" will become true after all data currently in the buffer
      has been read.


SSL session
===========

3.6 版新加入.

class ssl.SSLSession

   Session object used by "session".

   id

   time

   timeout

   ticket_lifetime_hint

   has_ticket


Security considerations
=======================


Best defaults
-------------

For **client use**, if you don't have any special requirements for
your security policy, it is highly recommended that you use the
"create_default_context()" function to create your SSL context. It
will load the system's trusted CA certificates, enable certificate
validation and hostname checking, and try to choose reasonably secure
protocol and cipher settings.

For example, here is how you would use the "smtplib.SMTP" class to
create a trusted, secure connection to a SMTP server:

   >>> import ssl, smtplib
   >>> smtp = smtplib.SMTP("mail.python.org", port=587)
   >>> context = ssl.create_default_context()
   >>> smtp.starttls(context=context)
   (220, b'2.0.0 Ready to start TLS')

If a client certificate is needed for the connection, it can be added
with "SSLContext.load_cert_chain()".

By contrast, if you create the SSL context by calling the "SSLContext"
constructor yourself, it will not have certificate validation nor
hostname checking enabled by default.  If you do so, please read the
paragraphs below to achieve a good security level.


Manual settings
---------------


Verifying certificates
~~~~~~~~~~~~~~~~~~~~~~

When calling the "SSLContext" constructor directly, "CERT_NONE" is the
default.  Since it does not authenticate the other peer, it can be
insecure, especially in client mode where most of time you would like
to ensure the authenticity of the server you're talking to. Therefore,
when in client mode, it is highly recommended to use "CERT_REQUIRED".
However, it is in itself not sufficient; you also have to check that
the server certificate, which can be obtained by calling
"SSLSocket.getpeercert()", matches the desired service.  For many
protocols and applications, the service can be identified by the
hostname; in this case, the "match_hostname()" function can be used.
This common check is automatically performed when
"SSLContext.check_hostname" is enabled.

3.7 版更變: Hostname matchings is now performed by OpenSSL. Python no
longer uses "match_hostname()".

In server mode, if you want to authenticate your clients using the SSL
layer (rather than using a higher-level authentication mechanism),
you'll also have to specify "CERT_REQUIRED" and similarly check the
client certificate.


Protocol versions
~~~~~~~~~~~~~~~~~

SSL versions 2 and 3 are considered insecure and are therefore
dangerous to use.  If you want maximum compatibility between clients
and servers, it is recommended to use "PROTOCOL_TLS_CLIENT" or
"PROTOCOL_TLS_SERVER" as the protocol version. SSLv2 and SSLv3 are
disabled by default.

   >>> client_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
   >>> client_context.options |= ssl.OP_NO_TLSv1
   >>> client_context.options |= ssl.OP_NO_TLSv1_1

The SSL context created above will only allow TLSv1.2 and later (if
supported by your system) connections to a server.
"PROTOCOL_TLS_CLIENT" implies certificate validation and hostname
checks by default. You have to load certificates into the context.


Cipher selection
~~~~~~~~~~~~~~~~

If you have advanced security requirements, fine-tuning of the ciphers
enabled when negotiating a SSL session is possible through the
"SSLContext.set_ciphers()" method.  Starting from Python 3.2.3, the
ssl module disables certain weak ciphers by default, but you may want
to further restrict the cipher choice. Be sure to read OpenSSL's
documentation about the cipher list format. If you want to check which
ciphers are enabled by a given cipher list, use
"SSLContext.get_ciphers()" or the "openssl ciphers" command on your
system.


Multi-processing
----------------

If using this module as part of a multi-processed application (using,
for example the "multiprocessing" or "concurrent.futures" modules), be
aware that OpenSSL's internal random number generator does not
properly handle forked processes.  Applications must change the PRNG
state of the parent process if they use any SSL feature with
"os.fork()".  Any successful call of "RAND_add()", "RAND_bytes()" or
"RAND_pseudo_bytes()" is sufficient.


TLS 1.3
=======

3.7 版新加入.

Python has provisional and experimental support for TLS 1.3 with
OpenSSL 1.1.1.  The new protocol behaves slightly differently than
previous version of TLS/SSL.  Some new TLS 1.3 features are not yet
available.

* TLS 1.3 uses a disjunct set of cipher suites. All AES-GCM and
  ChaCha20 cipher suites are enabled by default.  The method
  "SSLContext.set_ciphers()" cannot enable or disable any TLS 1.3
  ciphers yet, but "SSLContext.get_ciphers()" returns them.

* Session tickets are no longer sent as part of the initial handshake
  and are handled differently.  "SSLSocket.session" and "SSLSession"
  are not compatible with TLS 1.3.

* Client-side certificates are also no longer verified during the
  initial handshake.  A server can request a certificate at any time.
  Clients process certificate requests while they send or receive
  application data from the server.

* TLS 1.3 features like early data, deferred TLS client cert request,
  signature algorithm configuration, and rekeying are not supported
  yet.


LibreSSL support
================

LibreSSL is a fork of OpenSSL 1.0.1. The ssl module has limited
support for LibreSSL. Some features are not available when the ssl
module is compiled with LibreSSL.

* LibreSSL >= 2.6.1 no longer supports NPN. The methods
  "SSLContext.set_npn_protocols()" and
  "SSLSocket.selected_npn_protocol()" are not available.

* "SSLContext.set_default_verify_paths()" ignores the env vars
  "SSL_CERT_FILE" and "SSL_CERT_PATH" although
  "get_default_verify_paths()" still reports them.

也參考:

  Class "socket.socket"
     Documentation of underlying "socket" class

  SSL/TLS Strong Encryption: An Introduction
     Apache HTTP Server文档介绍

  **RFC 1422: Privacy Enhancement for Internet Electronic Mail: Part
  II: Certificate-Based Key Management**
     Steve Kent

  **RFC 4086: Randomness Requirements for Security**
     Donald E., Jeffrey I. Schiller

  **RFC 5280: Internet X.509 Public Key Infrastructure Certificate and
  Certificate Revocation List (CRL) Profile**
     D. Cooper

  **RFC 5246: The Transport Layer Security (TLS) Protocol Version
  1.2**
     T. Dierks et. al.

  **RFC 6066: Transport Layer Security (TLS) Extensions**
     D. Eastlake

  IANA TLS: Transport Layer Security (TLS) Parameters
     IANA

  **RFC 7525: Recommendations for Secure Use of Transport Layer
  Security (TLS) and Datagram Transport Layer Security (DTLS)**
     IETF

  Mozilla's Server Side TLS recommendations
     Mozilla
