Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cpython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
cpython
Commits
152efa2a
Commit
152efa2a
authored
May 16, 2010
by
Antoine Pitrou
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Issue #8550: Add first class `SSLContext` objects to the ssl module.
parent
8eac60d9
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
865 additions
and
284 deletions
+865
-284
Doc/library/ssl.rst
Doc/library/ssl.rst
+236
-47
Lib/ssl.py
Lib/ssl.py
+49
-22
Lib/test/capath/6e88d7b8.0
Lib/test/capath/6e88d7b8.0
+14
-0
Lib/test/capath/99d0fa06.0
Lib/test/capath/99d0fa06.0
+41
-0
Lib/test/test_ssl.py
Lib/test/test_ssl.py
+174
-29
Misc/NEWS
Misc/NEWS
+2
-0
Modules/_ssl.c
Modules/_ssl.c
+349
-186
No files found.
Doc/library/ssl.rst
View file @
152efa2a
...
...
@@ -36,6 +36,11 @@ additional :meth:`read` and :meth:`write` methods, along with a method,
connection, and a method, :meth:`cipher`, to retrieve the cipher being used for
the secure connection.
For more sophisticated applications, the :class:`ssl.SSLContext` class
helps manage settings and certificates, which can then be inherited
by SSL sockets created through the :meth:`SSLContext.wrap_socket` method.
Functions, Constants, and Exceptions
------------------------------------
...
...
@@ -64,19 +69,6 @@ Functions, Constants, and Exceptions
connection. See the discussion of :ref:`ssl-certificates` for more
information on how the certificate is stored in the ``certfile``.
Often the private key is stored in the same file as the certificate; in this
case, only the ``certfile`` parameter need be passed. If the private key is
stored in a separate file, both parameters must be used. If the private key
is stored in the ``certfile``, 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-----
The parameter ``server_side`` is a boolean which identifies whether
server-side or client-side behavior is desired from this socket.
...
...
@@ -208,24 +200,36 @@ Functions, Constants, and Exceptions
.. data:: CERT_NONE
Value to pass to the ``cert_reqs`` parameter to :func:`sslobject` when no
certificates will be required or validated from the other side of the socket
connection.
Possible value for :attr:`SSLContext.verify_mode`, or the ``cert_reqs``
parameter to :func:`wrap_socket`. In this mode (the default), no
certificates will be required from the other side of the socket connection.
If a certificate is received from the other end, no attempt to validate it
is made.
See the discussion of :ref:`ssl-security` below.
.. data:: CERT_OPTIONAL
Value to pass to the ``cert_reqs`` parameter to :func:`sslobject` when no
certificates will be required from the other side of the socket connection,
but if they are provided, will be validated. Note that use of this setting
requires a valid certificate validation file also be passed as a value of the
``ca_certs`` parameter.
Possible value for :attr:`SSLContext.verify_mode`, or the ``cert_reqs``
parameter to :func:`wrap_socket`. In this mode no certificates will be
required from the other side of the socket connection; but if they
are provided, validation will be attempted and an :class:`SSLError`
will be raised on failure.
Use of this setting requires a valid set of CA certificates to
be passed, either to :meth:`SSLContext.load_verify_locations` or as a
value of the ``ca_certs`` parameter to :func:`wrap_socket`.
.. data:: CERT_REQUIRED
Value to pass to the ``cert_reqs`` parameter to :func:`sslobject` when
certificates will be required from the other side of the socket connection.
Note that use of this setting requires a valid certificate validation file
also be passed as a value of the ``ca_certs`` parameter.
Possible value for :attr:`SSLContext.verify_mode`, or the ``cert_reqs``
parameter to :func:`wrap_socket`. In this mode, certificates are
required from the other side of the socket connection; an :class:`SSLError`
will be raised if no certificate is provided, or if its validation fails.
Use of this setting requires a valid set of CA certificates to
be passed, either to :meth:`SSLContext.load_verify_locations` or as a
value of the ``ca_certs`` parameter to :func:`wrap_socket`.
.. data:: PROTOCOL_SSLv2
...
...
@@ -284,8 +288,8 @@ Functions, Constants, and Exceptions
.. versionadded:: 3.2
SSL
Socket Objec
ts
-----------
------
SSL
Socke
ts
-----------
.. method:: SSLSocket.read(nbytes=1024, buffer=None)
...
...
@@ -371,6 +375,83 @@ SSLSocket Objects
returned socket should always be used for further communication with the
other side of the connection, rather than the original socket.
SSL Contexts
------------
.. class:: SSLContext(protocol)
An object holding various data longer-lived than single SSL connections,
such as SSL configuration options, certificate(s) and private key(s).
You must pass *protocol* which must be one of the ``PROTOCOL_*`` constants
defined in this module. :data:`PROTOCOL_SSLv23` is recommended for
maximum interoperability.
:class:`SSLContext` objects have the following methods and attributes:
.. method:: SSLContext.load_cert_chain(certfile, keyfile=None)
Load a private key and the corresponding certificate. The *certfile*
string must be the path to a single file in PEM format containing the
certificate as well as any number of CA certificates needed to establish
the certificate's authenticity. The *keyfile* string, if present, must
point to a file containing the private key in. Otherwise the private
key will be taken from *certfile* as well. See the discussion of
:ref:`ssl-certificates` for more information on how the certificate
is stored in the *certfile*.
An :class:`SSLError` is raised if the private key doesn't
match with the certificate.
.. method:: SSLContext.load_verify_locations(cafile=None, capath=None)
Load a set of "certification authority" (CA) certificates used to validate
other peers' certificates when :data:`verify_mode` is other than
:data:`CERT_NONE`. At least one of *cafile* or *capath* must be specified.
The *cafile* string, if present, is the path to a file of concatenated
CA certificates in PEM format. See the discussion of
:ref:`ssl-certificates` for more information about how to arrange the
certificates in this file.
The *capath* string, if present, is
the path to a directory containing several CA certificates in PEM format,
following an `OpenSSL specific layout
<http://www.openssl.org/docs/ssl/SSL_CTX_load_verify_locations.html>`_.
.. method:: SSLContext.set_ciphers(ciphers)
Set the available ciphers for sockets created with this context.
It should be a string in the `OpenSSL cipher list format
<http://www.openssl.org/docs/apps/ciphers.html#CIPHER_LIST_FORMAT>`_.
If no cipher can be selected (because compile-time options or other
configuration forbids use of all the specified ciphers), an
:class:`SSLError` will be raised.
.. note::
when connected, the :meth:`SSLSocket.cipher` method of SSL sockets will
give the currently selected cipher.
.. method:: SSLContext.wrap_socket(sock, server_side=False, do_handshake_on_connect=True, suppress_ragged_eofs=True)
Wrap an existing Python socket *sock* and return an :class:`SSLSocket`
object. The SSL socket is tied to the context, its settings and
certificates. The parameters *server_side*, *do_handshake_on_connect*
and *suppress_ragged_eofs* have the same meaning as in the top-level
:func:`wrap_socket` function.
.. attribute:: SSLContext.protocol
The protocol version chosen when constructing the context. This attribute
is read-only.
.. attribute:: SSLContext.verify_mode
Whether to try to verify other peers' certificates and how to behave
if verification fails. This attribute must be one of
:data:`CERT_NONE`, :data:`CERT_OPTIONAL` or :data:`CERT_REQUIRED`.
.. index:: single: certificates
.. index:: single: X509 certificate
...
...
@@ -416,6 +497,9 @@ and a footer line::
... (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,
...
...
@@ -439,6 +523,9 @@ certification authority's 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
...
...
@@ -458,6 +545,25 @@ peer is supposed to furnish the other certificates necessary to chain from its
certificate to a root certificate. See :rfc:`4158` for more discussion of the
way in which certification chains can be built.
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 :meth:`SSLContext.load_cert_chain`
and :func:`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
...
...
@@ -530,8 +636,7 @@ certificate, sends some bytes, and reads part of the response::
print(pprint.pformat(ssl_sock.getpeercert()))
# Set a simple HTTP request -- use http.client in actual code.
ssl_sock.write("""GET / HTTP/1.0\r
Host: www.verisign.com\r\n\r\n""")
ssl_sock.write(b"GET / HTTP/1.0\r\nHost: www.verisign.com\r\n\r\n")
# Read a chunk of data. Will not necessarily
# read all the data returned by the server.
...
...
@@ -561,39 +666,91 @@ this::
which is a fairly poorly-formed ``subject`` field.
This other example first creates an SSL context, instructs it to verify
certificates sent by peers, and feeds it a set of recognized certificate
authorities (CA)::
>>> context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
>>> context.verify_mode = ssl.CERT_OPTIONAL
>>> context.load_verify_locations("/etc/ssl/certs/ca-bundle.crt")
(it is assumed 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)
When you use the context to connect to a server, :const:`CERT_OPTIONAL`
validates the server certificate: it ensures that the server certificate
was signed with one of the CA certificates, and checks the signature for
correctness::
>>> conn = context.wrap_socket(socket.socket(socket.AF_INET))
>>> conn.connect(("linuxfr.org", 443))
You should then fetch the certificate and check its fields for conformity.
Here, the ``commonName`` field in the ``subject`` matches the desired HTTPS
host ``linuxfr.org``::
>>> pprint.pprint(conn.getpeercert())
{'notAfter': 'Jun 26 21:41:46 2011 GMT',
'subject': ((('commonName', 'linuxfr.org'),),),
'subjectAltName': (('DNS', 'linuxfr.org'), ('othername', '<unsupported>'))}
Now that you are assured of its authenticity, you can proceed to talk with
the server::
>>> conn.write(b"HEAD / HTTP/1.0\r\nHost: linuxfr.org\r\n\r\n")
38
>>> pprint.pprint(conn.read().split(b"\r\n"))
[b'HTTP/1.1 302 Found',
b'Date: Sun, 16 May 2010 13:43:28 GMT',
b'Server: Apache/2.2',
b'Location: https://linuxfr.org/pub/',
b'Vary: Accept-Encoding',
b'Connection: close',
b'Content-Type: text/html; charset=iso-8859-1',
b'',
b'']
See the discussion of :ref:`ssl-security` below.
Server-side operation
^^^^^^^^^^^^^^^^^^^^^
For server operation, typically you'd need to have a server certificate, and
private key, each in a file. You'd open a socket, bind it to a port, call
:meth:`listen` on it, then start waiting for clients to connect::
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 :meth:`listen` on it, and start
waiting for clients to connect::
import socket, ssl
context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
context.load_cert_chain(certfile="mycertfile", keyfile="mykeyfile")
bindsocket = socket.socket()
bindsocket.bind(('myaddr.mydomain.com', 10023))
bindsocket.listen(5)
When
one did, you'd call :meth:`accept` on the socket to get the new socket from
the other end, and use :func:`wrap_socket` to create a server-side SSL context
for it
::
When
a client connects, you'll call :meth:`accept` on the socket to get the
new socket from the other end, and use the context's :meth:`SSLContext.wrap_socket`
method to create a server-side SSL socket for the connection
::
while True:
newsocket, fromaddr = bindsocket.accept()
connstream = ssl.wrap_socket(newsocket,
server_side=True,
certfile="mycertfile",
keyfile="mykeyfile",
ssl_version=ssl.PROTOCOL_TLSv1)
deal_with_client(connstream)
Then you'd read data from the ``connstream`` and do something with it till you
connstream = context.wrap_socket(newsocket, server_side=True)
try:
deal_with_client(connstream)
finally:
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.read()
#
null
data means the client is finished with us
#
empty
data means the client is finished with us
while data:
if not do_something(connstream, data):
# we'll assume do_something returns False
...
...
@@ -601,9 +758,41 @@ are finished with the client (or the client is finished with you)::
break
data = connstream.read()
# finished with client
connstream.close()
And go back to listening for new client connections.
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).
.. _ssl-security:
Security considerations
-----------------------
Verifying certificates
^^^^^^^^^^^^^^^^^^^^^^
:const:`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
:const:`CERT_REQUIRED`. However, it is in itself not sufficient; you also
have to check that the server certificate (obtained with
:meth:`SSLSocket.getpeercert`) matches the desired service. The exact way
of doing so depends on the higher-level protocol used; for example, with
HTTPS, you'll check that the host name in the URL matches either the
``commonName`` field in the ``subjectName``, or one of the ``DNS`` fields
in the ``subjectAltName``.
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 :const:`CERT_REQUIRED` and similarly check the client certificate.
.. note::
In client mode, :const:`CERT_OPTIONAL` and :const:`CERT_REQUIRED` are
equivalent unless anonymous ciphers are enabled (they are disabled
by default).
.. seealso::
...
...
Lib/ssl.py
View file @
152efa2a
...
...
@@ -59,7 +59,7 @@ import textwrap
import
_ssl
# if we can't import it, let the error propagate
from
_ssl
import
OPENSSL_VERSION_NUMBER
,
OPENSSL_VERSION_INFO
,
OPENSSL_VERSION
from
_ssl
import
SSLError
from
_ssl
import
_SSLContext
,
SSLError
from
_ssl
import
CERT_NONE
,
CERT_OPTIONAL
,
CERT_REQUIRED
from
_ssl
import
(
PROTOCOL_SSLv2
,
PROTOCOL_SSLv3
,
PROTOCOL_SSLv23
,
PROTOCOL_TLSv1
)
...
...
@@ -84,8 +84,29 @@ import base64 # for DER-to-PEM translation
import
traceback
import
errno
class
SSLSocket
(
socket
):
class
SSLContext
(
_SSLContext
):
"""An SSLContext holds various SSL-related configuration options and
data, such as certificates and possibly a private key."""
__slots__
=
(
'protocol'
,)
def
__new__
(
cls
,
protocol
,
*
args
,
**
kwargs
):
return
_SSLContext
.
__new__
(
cls
,
protocol
)
def
__init__
(
self
,
protocol
):
self
.
protocol
=
protocol
def
wrap_socket
(
self
,
sock
,
server_side
=
False
,
do_handshake_on_connect
=
True
,
suppress_ragged_eofs
=
True
):
return
SSLSocket
(
sock
=
sock
,
server_side
=
server_side
,
do_handshake_on_connect
=
do_handshake_on_connect
,
suppress_ragged_eofs
=
suppress_ragged_eofs
,
_context
=
self
)
class
SSLSocket
(
socket
):
"""This class implements a subtype of socket.socket that wraps
the underlying OS socket in an SSL context when necessary, and
provides read and write methods over that channel."""
...
...
@@ -95,8 +116,31 @@ class SSLSocket(socket):
ssl_version
=
PROTOCOL_SSLv23
,
ca_certs
=
None
,
do_handshake_on_connect
=
True
,
family
=
AF_INET
,
type
=
SOCK_STREAM
,
proto
=
0
,
fileno
=
None
,
suppress_ragged_eofs
=
True
,
ciphers
=
None
):
suppress_ragged_eofs
=
True
,
ciphers
=
None
,
_context
=
None
):
if
_context
:
self
.
context
=
_context
else
:
if
certfile
and
not
keyfile
:
keyfile
=
certfile
self
.
context
=
SSLContext
(
ssl_version
)
self
.
context
.
verify_mode
=
cert_reqs
if
ca_certs
:
self
.
context
.
load_verify_locations
(
ca_certs
)
if
certfile
:
self
.
context
.
load_cert_chain
(
certfile
,
keyfile
)
if
ciphers
:
self
.
context
.
set_ciphers
(
ciphers
)
self
.
keyfile
=
keyfile
self
.
certfile
=
certfile
self
.
cert_reqs
=
cert_reqs
self
.
ssl_version
=
ssl_version
self
.
ca_certs
=
ca_certs
self
.
ciphers
=
ciphers
self
.
do_handshake_on_connect
=
do_handshake_on_connect
self
.
suppress_ragged_eofs
=
suppress_ragged_eofs
connected
=
False
if
sock
is
not
None
:
socket
.
__init__
(
self
,
...
...
@@ -119,18 +163,12 @@ class SSLSocket(socket):
else
:
socket
.
__init__
(
self
,
family
=
family
,
type
=
type
,
proto
=
proto
)
if
certfile
and
not
keyfile
:
keyfile
=
certfile
self
.
_closed
=
False
self
.
_sslobj
=
None
if
connected
:
# create the SSL object
try
:
self
.
_sslobj
=
_ssl
.
sslwrap
(
self
,
server_side
,
keyfile
,
certfile
,
cert_reqs
,
ssl_version
,
ca_certs
,
ciphers
)
self
.
_sslobj
=
self
.
context
.
_wrap_socket
(
self
,
server_side
)
if
do_handshake_on_connect
:
timeout
=
self
.
gettimeout
()
if
timeout
==
0.0
:
...
...
@@ -142,15 +180,6 @@ class SSLSocket(socket):
self
.
close
()
raise
x
self
.
keyfile
=
keyfile
self
.
certfile
=
certfile
self
.
cert_reqs
=
cert_reqs
self
.
ssl_version
=
ssl_version
self
.
ca_certs
=
ca_certs
self
.
ciphers
=
ciphers
self
.
do_handshake_on_connect
=
do_handshake_on_connect
self
.
suppress_ragged_eofs
=
suppress_ragged_eofs
def
dup
(
self
):
raise
NotImplemented
(
"Can't dup() %s instances"
%
self
.
__class__
.
__name__
)
...
...
@@ -331,9 +360,7 @@ class SSLSocket(socket):
if
self
.
_sslobj
:
raise
ValueError
(
"attempt to connect already-connected SSLSocket!"
)
socket
.
connect
(
self
,
addr
)
self
.
_sslobj
=
_ssl
.
sslwrap
(
self
,
False
,
self
.
keyfile
,
self
.
certfile
,
self
.
cert_reqs
,
self
.
ssl_version
,
self
.
ca_certs
,
self
.
ciphers
)
self
.
_sslobj
=
self
.
context
.
_wrap_socket
(
self
,
False
)
try
:
if
self
.
do_handshake_on_connect
:
self
.
do_handshake
()
...
...
Lib/test/capath/6e88d7b8.0
0 → 100644
View file @
152efa2a
-----BEGIN CERTIFICATE-----
MIICLDCCAdYCAQAwDQYJKoZIhvcNAQEEBQAwgaAxCzAJBgNVBAYTAlBUMRMwEQYD
VQQIEwpRdWVlbnNsYW5kMQ8wDQYDVQQHEwZMaXNib2ExFzAVBgNVBAoTDk5ldXJv
bmlvLCBMZGEuMRgwFgYDVQQLEw9EZXNlbnZvbHZpbWVudG8xGzAZBgNVBAMTEmJy
dXR1cy5uZXVyb25pby5wdDEbMBkGCSqGSIb3DQEJARYMc2FtcG9AaWtpLmZpMB4X
DTk2MDkwNTAzNDI0M1oXDTk2MTAwNTAzNDI0M1owgaAxCzAJBgNVBAYTAlBUMRMw
EQYDVQQIEwpRdWVlbnNsYW5kMQ8wDQYDVQQHEwZMaXNib2ExFzAVBgNVBAoTDk5l
dXJvbmlvLCBMZGEuMRgwFgYDVQQLEw9EZXNlbnZvbHZpbWVudG8xGzAZBgNVBAMT
EmJydXR1cy5uZXVyb25pby5wdDEbMBkGCSqGSIb3DQEJARYMc2FtcG9AaWtpLmZp
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAL7+aty3S1iBA/+yxjxv4q1MUTd1kjNw
L4lYKbpzzlmC5beaQXeQ2RmGMTXU+mDvuqItjVHOK3DvPK7lTcSGftUCAwEAATAN
BgkqhkiG9w0BAQQFAANBAFqPEKFjk6T6CKTHvaQeEAsX0/8YHPHqH/9AnhSjrwuX
9EBc0n6bVGhN7XaXd6sJ7dym9sbsWxb+pJdurnkxjx4=
-----END CERTIFICATE-----
Lib/test/capath/99d0fa06.0
0 → 100644
View file @
152efa2a
-----BEGIN CERTIFICATE-----
MIIHPTCCBSWgAwIBAgIBADANBgkqhkiG9w0BAQQFADB5MRAwDgYDVQQKEwdSb290
IENBMR4wHAYDVQQLExVodHRwOi8vd3d3LmNhY2VydC5vcmcxIjAgBgNVBAMTGUNB
IENlcnQgU2lnbmluZyBBdXRob3JpdHkxITAfBgkqhkiG9w0BCQEWEnN1cHBvcnRA
Y2FjZXJ0Lm9yZzAeFw0wMzAzMzAxMjI5NDlaFw0zMzAzMjkxMjI5NDlaMHkxEDAO
BgNVBAoTB1Jvb3QgQ0ExHjAcBgNVBAsTFWh0dHA6Ly93d3cuY2FjZXJ0Lm9yZzEi
MCAGA1UEAxMZQ0EgQ2VydCBTaWduaW5nIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJ
ARYSc3VwcG9ydEBjYWNlcnQub3JnMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
CgKCAgEAziLA4kZ97DYoB1CW8qAzQIxL8TtmPzHlawI229Z89vGIj053NgVBlfkJ
8BLPRoZzYLdufujAWGSuzbCtRRcMY/pnCujW0r8+55jE8Ez64AO7NV1sId6eINm6
zWYyN3L69wj1x81YyY7nDl7qPv4coRQKFWyGhFtkZip6qUtTefWIonvuLwphK42y
fk1WpRPs6tqSnqxEQR5YYGUFZvjARL3LlPdCfgv3ZWiYUQXw8wWRBB0bF4LsyFe7
w2t6iPGwcswlWyCR7BYCEo8y6RcYSNDHBS4CMEK4JZwFaz+qOqfrU0j36NK2B5jc
G8Y0f3/JHIJ6BVgrCFvzOKKrF11myZjXnhCLotLddJr3cQxyYN/Nb5gznZY0dj4k
epKwDpUeb+agRThHqtdB7Uq3EvbXG4OKDy7YCbZZ16oE/9KTfWgu3YtLq1i6L43q
laegw1SJpfvbi1EinbLDvhG+LJGGi5Z4rSDTii8aP8bQUWWHIbEZAWV/RRyH9XzQ
QUxPKZgh/TMfdQwEUfoZd9vUFBzugcMd9Zi3aQaRIt0AUMyBMawSB3s42mhb5ivU
fslfrejrckzzAeVLIL+aplfKkQABi6F1ITe1Yw1nPkZPcCBnzsXWWdsC4PDSy826
YreQQejdIOQpvGQpQsgi3Hia/0PsmBsJUUtaWsJx8cTLc6nloQsCAwEAAaOCAc4w
ggHKMB0GA1UdDgQWBBQWtTIb1Mfz4OaO873SsDrusjkY0TCBowYDVR0jBIGbMIGY
gBQWtTIb1Mfz4OaO873SsDrusjkY0aF9pHsweTEQMA4GA1UEChMHUm9vdCBDQTEe
MBwGA1UECxMVaHR0cDovL3d3dy5jYWNlcnQub3JnMSIwIAYDVQQDExlDQSBDZXJ0
IFNpZ25pbmcgQXV0aG9yaXR5MSEwHwYJKoZIhvcNAQkBFhJzdXBwb3J0QGNhY2Vy
dC5vcmeCAQAwDwYDVR0TAQH/BAUwAwEB/zAyBgNVHR8EKzApMCegJaAjhiFodHRw
czovL3d3dy5jYWNlcnQub3JnL3Jldm9rZS5jcmwwMAYJYIZIAYb4QgEEBCMWIWh0
dHBzOi8vd3d3LmNhY2VydC5vcmcvcmV2b2tlLmNybDA0BglghkgBhvhCAQgEJxYl
aHR0cDovL3d3dy5jYWNlcnQub3JnL2luZGV4LnBocD9pZD0xMDBWBglghkgBhvhC
AQ0ESRZHVG8gZ2V0IHlvdXIgb3duIGNlcnRpZmljYXRlIGZvciBGUkVFIGhlYWQg
b3ZlciB0byBodHRwOi8vd3d3LmNhY2VydC5vcmcwDQYJKoZIhvcNAQEEBQADggIB
ACjH7pyCArpcgBLKNQodgW+JapnM8mgPf6fhjViVPr3yBsOQWqy1YPaZQwGjiHCc
nWKdpIevZ1gNMDY75q1I08t0AoZxPuIrA2jxNGJARjtT6ij0rPtmlVOKTV39O9lg
18p5aTuxZZKmxoGCXJzN600BiqXfEVWqFcofN8CCmHBh22p8lqOOLlQ+TyGpkO/c
gr/c6EWtTZBzCDyUZbAEmXZ/4rzCahWqlwQ3JNgelE5tDlG+1sSPypZt90Pf6DBl
Jzt7u0NDY8RD97LsaMzhGY4i+5jhe1o+ATc7iwiwovOVThrLm82asduycPAtStvY
sONvRUgzEv/+PDIqVPfE94rwiCPCR/5kenHA0R6mY7AHfqQv0wGP3J8rtsYIqQ+T
SCX8Ev2fQtzzxD72V7DX3WnRBnc0CkvSyqD/HMaMyRa+xMwyN2hzXwj7UfdJUzYF
CpUCTPJ5GhD22Dp1nPMd8aINcGeGG7MW9S/lpOt5hvk9C8JzC6WZrG/8Z7jlLwum
GCSNe9FINSkYQKyTYOGWhlC0elnYjyELn8+CkcY7v2vcB5G5l1YjqrZslMZIBjzk
zk6q5PYvCdxTby78dOs6Y5nCpqyJvKeyRKANihDjbPIky/qbn3BHLt4Ui9SyIAmW
omTxJBzcoTWcFbLUvFUufQb1nA5V9FrWk9p2rSVzTMVD
-----END CERTIFICATE-----
Lib/test/test_ssl.py
View file @
152efa2a
...
...
@@ -10,6 +10,7 @@ import gc
import
os
import
errno
import
pprint
import
tempfile
import
urllib.parse
,
urllib
.
request
import
traceback
import
asyncore
...
...
@@ -25,8 +26,30 @@ except ImportError:
skip_expected
=
True
HOST
=
support
.
HOST
CERTFILE
=
None
SVN_PYTHON_ORG_ROOT_CERT
=
None
PROTOCOLS
=
[
ssl
.
PROTOCOL_SSLv2
,
ssl
.
PROTOCOL_SSLv3
,
ssl
.
PROTOCOL_SSLv23
,
ssl
.
PROTOCOL_TLSv1
]
data_file
=
lambda
name
:
os
.
path
.
join
(
os
.
path
.
dirname
(
__file__
),
name
)
fsencode
=
lambda
name
:
name
.
encode
(
sys
.
getfilesystemencoding
(),
"surrogateescape"
)
CERTFILE
=
data_file
(
"keycert.pem"
)
BYTES_CERTFILE
=
fsencode
(
CERTFILE
)
ONLYCERT
=
data_file
(
"ssl_cert.pem"
)
ONLYKEY
=
data_file
(
"ssl_key.pem"
)
BYTES_ONLYCERT
=
fsencode
(
ONLYCERT
)
BYTES_ONLYKEY
=
fsencode
(
ONLYKEY
)
CAPATH
=
data_file
(
"capath"
)
BYTES_CAPATH
=
fsencode
(
CAPATH
)
SVN_PYTHON_ORG_ROOT_CERT
=
data_file
(
"https_svn_python_org_root.pem"
)
EMPTYCERT
=
data_file
(
"nullcert.pem"
)
BADCERT
=
data_file
(
"badcert.pem"
)
WRONGCERT
=
data_file
(
"XXXnonexisting.pem"
)
BADKEY
=
data_file
(
"badkey.pem"
)
def
handle_error
(
prefix
):
exc_format
=
' '
.
join
(
traceback
.
format_exception
(
*
sys
.
exc_info
()))
...
...
@@ -34,7 +57,7 @@ def handle_error(prefix):
sys
.
stdout
.
write
(
prefix
+
exc_format
)
class
BasicTests
(
unittest
.
TestCase
):
class
Basic
Socket
Tests
(
unittest
.
TestCase
):
def
test_constants
(
self
):
ssl
.
PROTOCOL_SSLv2
...
...
@@ -116,11 +139,10 @@ class BasicTests(unittest.TestCase):
s
=
ssl
.
wrap_socket
(
socket
.
socket
(
socket
.
AF_INET
),
cert_reqs
=
ssl
.
CERT_NONE
,
ciphers
=
"DEFAULT"
)
s
.
connect
(
remote
)
# Error checking occurs when connecting, because the SSL context
# isn't created before.
s
=
ssl
.
wrap_socket
(
socket
.
socket
(
socket
.
AF_INET
),
cert_reqs
=
ssl
.
CERT_NONE
,
ciphers
=
"^$:,;?*'dorothyx"
)
# Error checking can happen at instantiation or when connecting
with
self
.
assertRaisesRegexp
(
ssl
.
SSLError
,
"No cipher can be selected"
):
s
=
ssl
.
wrap_socket
(
socket
.
socket
(
socket
.
AF_INET
),
cert_reqs
=
ssl
.
CERT_NONE
,
ciphers
=
"^$:,;?*'dorothyx"
)
s
.
connect
(
remote
)
@
support
.
cpython_only
...
...
@@ -143,33 +165,160 @@ class BasicTests(unittest.TestCase):
self
.
assertEqual
(
timeout
,
ss
.
gettimeout
())
class
ContextTests
(
unittest
.
TestCase
):
def
test_constructor
(
self
):
ctx
=
ssl
.
SSLContext
(
ssl
.
PROTOCOL_SSLv2
)
ctx
=
ssl
.
SSLContext
(
ssl
.
PROTOCOL_SSLv23
)
ctx
=
ssl
.
SSLContext
(
ssl
.
PROTOCOL_SSLv3
)
ctx
=
ssl
.
SSLContext
(
ssl
.
PROTOCOL_TLSv1
)
self
.
assertRaises
(
TypeError
,
ssl
.
SSLContext
)
self
.
assertRaises
(
ValueError
,
ssl
.
SSLContext
,
-
1
)
self
.
assertRaises
(
ValueError
,
ssl
.
SSLContext
,
42
)
def
test_protocol
(
self
):
for
proto
in
PROTOCOLS
:
ctx
=
ssl
.
SSLContext
(
proto
)
self
.
assertEqual
(
ctx
.
protocol
,
proto
)
def
test_ciphers
(
self
):
ctx
=
ssl
.
SSLContext
(
ssl
.
PROTOCOL_TLSv1
)
ctx
.
set_ciphers
(
"ALL"
)
ctx
.
set_ciphers
(
"DEFAULT"
)
with
self
.
assertRaisesRegexp
(
ssl
.
SSLError
,
"No cipher can be selected"
):
ctx
.
set_ciphers
(
"^$:,;?*'dorothyx"
)
def
test_verify
(
self
):
ctx
=
ssl
.
SSLContext
(
ssl
.
PROTOCOL_TLSv1
)
# Default value
self
.
assertEqual
(
ctx
.
verify_mode
,
ssl
.
CERT_NONE
)
ctx
.
verify_mode
=
ssl
.
CERT_OPTIONAL
self
.
assertEqual
(
ctx
.
verify_mode
,
ssl
.
CERT_OPTIONAL
)
ctx
.
verify_mode
=
ssl
.
CERT_REQUIRED
self
.
assertEqual
(
ctx
.
verify_mode
,
ssl
.
CERT_REQUIRED
)
ctx
.
verify_mode
=
ssl
.
CERT_NONE
self
.
assertEqual
(
ctx
.
verify_mode
,
ssl
.
CERT_NONE
)
with
self
.
assertRaises
(
TypeError
):
ctx
.
verify_mode
=
None
with
self
.
assertRaises
(
ValueError
):
ctx
.
verify_mode
=
42
def
test_load_cert_chain
(
self
):
ctx
=
ssl
.
SSLContext
(
ssl
.
PROTOCOL_TLSv1
)
# Combined key and cert in a single file
ctx
.
load_cert_chain
(
CERTFILE
)
ctx
.
load_cert_chain
(
CERTFILE
,
keyfile
=
CERTFILE
)
self
.
assertRaises
(
TypeError
,
ctx
.
load_cert_chain
,
keyfile
=
CERTFILE
)
with
self
.
assertRaisesRegexp
(
ssl
.
SSLError
,
"system lib"
):
ctx
.
load_cert_chain
(
WRONGCERT
)
with
self
.
assertRaisesRegexp
(
ssl
.
SSLError
,
"PEM lib"
):
ctx
.
load_cert_chain
(
BADCERT
)
with
self
.
assertRaisesRegexp
(
ssl
.
SSLError
,
"PEM lib"
):
ctx
.
load_cert_chain
(
EMPTYCERT
)
# Separate key and cert
ctx
.
load_cert_chain
(
ONLYCERT
,
ONLYKEY
)
ctx
.
load_cert_chain
(
certfile
=
ONLYCERT
,
keyfile
=
ONLYKEY
)
ctx
.
load_cert_chain
(
certfile
=
BYTES_ONLYCERT
,
keyfile
=
BYTES_ONLYKEY
)
with
self
.
assertRaisesRegexp
(
ssl
.
SSLError
,
"PEM lib"
):
ctx
.
load_cert_chain
(
ONLYCERT
)
with
self
.
assertRaisesRegexp
(
ssl
.
SSLError
,
"PEM lib"
):
ctx
.
load_cert_chain
(
ONLYKEY
)
with
self
.
assertRaisesRegexp
(
ssl
.
SSLError
,
"PEM lib"
):
ctx
.
load_cert_chain
(
certfile
=
ONLYKEY
,
keyfile
=
ONLYCERT
)
# Mismatching key and cert
with
self
.
assertRaisesRegexp
(
ssl
.
SSLError
,
"key values mismatch"
):
ctx
.
load_cert_chain
(
CERTFILE
,
ONLYKEY
)
def
test_load_verify_locations
(
self
):
ctx
=
ssl
.
SSLContext
(
ssl
.
PROTOCOL_TLSv1
)
ctx
.
load_verify_locations
(
CERTFILE
)
ctx
.
load_verify_locations
(
cafile
=
CERTFILE
,
capath
=
None
)
ctx
.
load_verify_locations
(
BYTES_CERTFILE
)
ctx
.
load_verify_locations
(
cafile
=
BYTES_CERTFILE
,
capath
=
None
)
self
.
assertRaises
(
TypeError
,
ctx
.
load_verify_locations
)
self
.
assertRaises
(
TypeError
,
ctx
.
load_verify_locations
,
None
,
None
)
with
self
.
assertRaisesRegexp
(
ssl
.
SSLError
,
"system lib"
):
ctx
.
load_verify_locations
(
WRONGCERT
)
with
self
.
assertRaisesRegexp
(
ssl
.
SSLError
,
"PEM lib"
):
ctx
.
load_verify_locations
(
BADCERT
)
ctx
.
load_verify_locations
(
CERTFILE
,
CAPATH
)
ctx
.
load_verify_locations
(
CERTFILE
,
capath
=
BYTES_CAPATH
)
class
NetworkedTests
(
unittest
.
TestCase
):
def
test_connect
(
self
):
s
=
ssl
.
wrap_socket
(
socket
.
socket
(
socket
.
AF_INET
),
cert_reqs
=
ssl
.
CERT_NONE
)
s
.
connect
((
"svn.python.org"
,
443
))
c
=
s
.
getpeercert
()
if
c
:
self
.
fail
(
"Peer cert %s shouldn't be here!"
)
s
.
close
()
# this should fail because we have no verification certs
s
=
ssl
.
wrap_socket
(
socket
.
socket
(
socket
.
AF_INET
),
cert_reqs
=
ssl
.
CERT_REQUIRED
)
try
:
s
.
connect
((
"svn.python.org"
,
443
))
except
ssl
.
SSLError
:
pass
self
.
assertEqual
({},
s
.
getpeercert
())
finally
:
s
.
close
()
# this should fail because we have no verification certs
s
=
ssl
.
wrap_socket
(
socket
.
socket
(
socket
.
AF_INET
),
cert_reqs
=
ssl
.
CERT_REQUIRED
)
self
.
assertRaisesRegexp
(
ssl
.
SSLError
,
"certificate verify failed"
,
s
.
connect
,
(
"svn.python.org"
,
443
))
s
.
close
()
# this should succeed because we specify the root cert
s
=
ssl
.
wrap_socket
(
socket
.
socket
(
socket
.
AF_INET
),
cert_reqs
=
ssl
.
CERT_REQUIRED
,
ca_certs
=
SVN_PYTHON_ORG_ROOT_CERT
)
try
:
s
.
connect
((
"svn.python.org"
,
443
))
self
.
assertTrue
(
s
.
getpeercert
())
finally
:
s
.
close
()
def
test_connect_with_context
(
self
):
# Same as test_connect, but with a separately created context
ctx
=
ssl
.
SSLContext
(
ssl
.
PROTOCOL_SSLv23
)
s
=
ctx
.
wrap_socket
(
socket
.
socket
(
socket
.
AF_INET
))
s
.
connect
((
"svn.python.org"
,
443
))
try
:
self
.
assertEqual
({},
s
.
getpeercert
())
finally
:
s
.
close
()
# This should fail because we have no verification certs
ctx
.
verify_mode
=
ssl
.
CERT_REQUIRED
s
=
ctx
.
wrap_socket
(
socket
.
socket
(
socket
.
AF_INET
))
self
.
assertRaisesRegexp
(
ssl
.
SSLError
,
"certificate verify failed"
,
s
.
connect
,
(
"svn.python.org"
,
443
))
s
.
close
()
# This should succeed because we specify the root cert
ctx
.
load_verify_locations
(
SVN_PYTHON_ORG_ROOT_CERT
)
s
=
ctx
.
wrap_socket
(
socket
.
socket
(
socket
.
AF_INET
))
s
.
connect
((
"svn.python.org"
,
443
))
try
:
cert
=
s
.
getpeercert
()
self
.
assertTrue
(
cert
)
finally
:
s
.
close
()
def
test_connect_capath
(
self
):
# Verify server certificates using the `capath` argument
ctx
=
ssl
.
SSLContext
(
ssl
.
PROTOCOL_SSLv23
)
ctx
.
verify_mode
=
ssl
.
CERT_REQUIRED
ctx
.
load_verify_locations
(
capath
=
CAPATH
)
s
=
ctx
.
wrap_socket
(
socket
.
socket
(
socket
.
AF_INET
))
s
.
connect
((
"svn.python.org"
,
443
))
try
:
cert
=
s
.
getpeercert
()
self
.
assertTrue
(
cert
)
finally
:
s
.
close
()
# Same with a bytes `capath` argument
ctx
=
ssl
.
SSLContext
(
ssl
.
PROTOCOL_SSLv23
)
ctx
.
verify_mode
=
ssl
.
CERT_REQUIRED
ctx
.
load_verify_locations
(
capath
=
BYTES_CAPATH
)
s
=
ctx
.
wrap_socket
(
socket
.
socket
(
socket
.
AF_INET
))
s
.
connect
((
"svn.python.org"
,
443
))
try
:
cert
=
s
.
getpeercert
()
self
.
assertTrue
(
cert
)
finally
:
s
.
close
()
...
...
@@ -1227,18 +1376,14 @@ def test_main(verbose=False):
if
skip_expected
:
raise
unittest
.
SkipTest
(
"No SSL support"
)
global
CERTFILE
,
SVN_PYTHON_ORG_ROOT_CERT
CERTFILE
=
os
.
path
.
join
(
os
.
path
.
dirname
(
__file__
)
or
os
.
curdir
,
"keycert.pem"
)
SVN_PYTHON_ORG_ROOT_CERT
=
os
.
path
.
join
(
os
.
path
.
dirname
(
__file__
)
or
os
.
curdir
,
"https_svn_python_org_root.pem"
)
if
(
not
os
.
path
.
exists
(
CERTFILE
)
or
not
os
.
path
.
exists
(
SVN_PYTHON_ORG_ROOT_CERT
)):
raise
support
.
TestFailed
(
"Can't read certificate files!"
)
for
filename
in
[
CERTFILE
,
SVN_PYTHON_ORG_ROOT_CERT
,
BYTES_CERTFILE
,
ONLYCERT
,
ONLYKEY
,
BYTES_ONLYCERT
,
BYTES_ONLYKEY
,
BADCERT
,
BADKEY
,
EMPTYCERT
]:
if
not
os
.
path
.
exists
(
filename
):
raise
support
.
TestFailed
(
"Can't read certificate file %r"
%
filename
)
tests
=
[
Basic
Tests
]
tests
=
[
ContextTests
,
BasicSocket
Tests
]
if
support
.
is_resource_enabled
(
'network'
):
tests
.
append
(
NetworkedTests
)
...
...
Misc/NEWS
View file @
152efa2a
...
...
@@ -363,6 +363,8 @@ C-API
Library
-------
- Issue #8550: Add first class ``SSLContext`` objects to the ssl module.
- Issue #8681: Make the zlib module's error messages more informative when
the zlib itself doesn't give any detailed explanation.
...
...
Modules/_ssl.c
View file @
152efa2a
...
...
@@ -115,23 +115,29 @@ static unsigned int _ssl_locks_count = 0;
typedef
struct
{
PyObject_HEAD
PyObject
*
Socket
;
/* weakref to socket on which we're layered */
SSL_CTX
*
ctx
;
SSL
*
ssl
;
X509
*
peer_cert
;
int
shutdown_seen_zero
;
SSL_CTX
*
ctx
;
}
PySSLContext
;
}
PySSLObject
;
typedef
struct
{
PyObject_HEAD
PyObject
*
Socket
;
/* weakref to socket on which we're layered */
SSL
*
ssl
;
X509
*
peer_cert
;
int
shutdown_seen_zero
;
}
PySSLSocket
;
static
PyTypeObject
PySSLContext_Type
;
static
PyTypeObject
PySSLSocket_Type
;
static
PyTypeObject
PySSL_Type
;
static
PyObject
*
PySSL_SSLwrite
(
PySSLObject
*
self
,
PyObject
*
args
);
static
PyObject
*
PySSL_SSLread
(
PySSLObject
*
self
,
PyObject
*
args
);
static
PyObject
*
PySSL_SSLwrite
(
PySSLSocket
*
self
,
PyObject
*
args
);
static
PyObject
*
PySSL_SSLread
(
PySSLSocket
*
self
,
PyObject
*
args
);
static
int
check_socket_and_wait_for_timeout
(
PySocketSockObject
*
s
,
int
writing
);
static
PyObject
*
PySSL_peercert
(
PySSL
Objec
t
*
self
,
PyObject
*
args
);
static
PyObject
*
PySSL_cipher
(
PySSL
Objec
t
*
self
);
static
PyObject
*
PySSL_peercert
(
PySSL
Socke
t
*
self
,
PyObject
*
args
);
static
PyObject
*
PySSL_cipher
(
PySSL
Socke
t
*
self
);
#define PySSLObject_Check(v) (Py_TYPE(v) == &PySSL_Type)
#define PySSLContext_Check(v) (Py_TYPE(v) == &PySSLContext_Type)
#define PySSLSocket_Check(v) (Py_TYPE(v) == &PySSLSocket_Type)
typedef
enum
{
SOCKET_IS_NONBLOCKING
,
...
...
@@ -154,7 +160,7 @@ typedef enum {
*/
static
PyObject
*
PySSL_SetError
(
PySSL
Objec
t
*
obj
,
int
ret
,
char
*
filename
,
int
lineno
)
PySSL_SetError
(
PySSL
Socke
t
*
obj
,
int
ret
,
char
*
filename
,
int
lineno
)
{
PyObject
*
v
;
char
buf
[
2048
];
...
...
@@ -258,126 +264,28 @@ _setSSLError (char *errstr, int errcode, char *filename, int lineno) {
return
NULL
;
}
static
PySSLObject
*
newPySSLObject
(
PySocketSockObject
*
Sock
,
char
*
key_file
,
char
*
cert_file
,
enum
py_ssl_server_or_client
socket_type
,
enum
py_ssl_cert_requirements
certreq
,
enum
py_ssl_version
proto_version
,
char
*
cacerts_file
,
char
*
ciphers
)
static
PySSLSocket
*
newPySSLSocket
(
SSL_CTX
*
ctx
,
PySocketSockObject
*
sock
,
enum
py_ssl_server_or_client
socket_type
)
{
PySSLObject
*
self
;
char
*
errstr
=
NULL
;
int
ret
;
int
verification_mode
;
PySSLSocket
*
self
;
self
=
PyObject_New
(
PySSL
Object
,
&
PySSL_Type
);
/* Create new object */
self
=
PyObject_New
(
PySSL
Socket
,
&
PySSLSocket_Type
);
if
(
self
==
NULL
)
return
NULL
;
self
->
peer_cert
=
NULL
;
self
->
ssl
=
NULL
;
self
->
ctx
=
NULL
;
self
->
Socket
=
NULL
;
/* Make sure the SSL error state is initialized */
(
void
)
ERR_get_state
();
ERR_clear_error
();
if
((
key_file
&&
!
cert_file
)
||
(
!
key_file
&&
cert_file
))
{
errstr
=
ERRSTR
(
"Both the key & certificate files "
"must be specified"
);
goto
fail
;
}
if
((
socket_type
==
PY_SSL_SERVER
)
&&
((
key_file
==
NULL
)
||
(
cert_file
==
NULL
)))
{
errstr
=
ERRSTR
(
"Both the key & certificate files "
"must be specified for server-side operation"
);
goto
fail
;
}
PySSL_BEGIN_ALLOW_THREADS
if
(
proto_version
==
PY_SSL_VERSION_TLS1
)
self
->
ctx
=
SSL_CTX_new
(
TLSv1_method
());
/* Set up context */
else
if
(
proto_version
==
PY_SSL_VERSION_SSL3
)
self
->
ctx
=
SSL_CTX_new
(
SSLv3_method
());
/* Set up context */
else
if
(
proto_version
==
PY_SSL_VERSION_SSL2
)
self
->
ctx
=
SSL_CTX_new
(
SSLv2_method
());
/* Set up context */
else
if
(
proto_version
==
PY_SSL_VERSION_SSL23
)
self
->
ctx
=
SSL_CTX_new
(
SSLv23_method
());
/* Set up context */
PySSL_END_ALLOW_THREADS
if
(
self
->
ctx
==
NULL
)
{
errstr
=
ERRSTR
(
"Invalid SSL protocol variant specified."
);
goto
fail
;
}
if
(
ciphers
!=
NULL
)
{
ret
=
SSL_CTX_set_cipher_list
(
self
->
ctx
,
ciphers
);
if
(
ret
==
0
)
{
errstr
=
ERRSTR
(
"No cipher can be selected."
);
goto
fail
;
}
}
if
(
certreq
!=
PY_SSL_CERT_NONE
)
{
if
(
cacerts_file
==
NULL
)
{
errstr
=
ERRSTR
(
"No root certificates specified for "
"verification of other-side certificates."
);
goto
fail
;
}
else
{
PySSL_BEGIN_ALLOW_THREADS
ret
=
SSL_CTX_load_verify_locations
(
self
->
ctx
,
cacerts_file
,
NULL
);
PySSL_END_ALLOW_THREADS
if
(
ret
!=
1
)
{
_setSSLError
(
NULL
,
0
,
__FILE__
,
__LINE__
);
goto
fail
;
}
}
}
if
(
key_file
)
{
PySSL_BEGIN_ALLOW_THREADS
ret
=
SSL_CTX_use_PrivateKey_file
(
self
->
ctx
,
key_file
,
SSL_FILETYPE_PEM
);
PySSL_END_ALLOW_THREADS
if
(
ret
!=
1
)
{
_setSSLError
(
NULL
,
ret
,
__FILE__
,
__LINE__
);
goto
fail
;
}
PySSL_BEGIN_ALLOW_THREADS
ret
=
SSL_CTX_use_certificate_chain_file
(
self
->
ctx
,
cert_file
);
PySSL_END_ALLOW_THREADS
if
(
ret
!=
1
)
{
/*
fprintf(stderr, "ret is %d, errcode is %lu, %lu, with file \"%s\"\n",
ret, ERR_peek_error(), ERR_peek_last_error(), cert_file);
*/
if
(
ERR_peek_last_error
()
!=
0
)
{
_setSSLError
(
NULL
,
ret
,
__FILE__
,
__LINE__
);
goto
fail
;
}
}
}
/* ssl compatibility */
SSL_CTX_set_options
(
self
->
ctx
,
SSL_OP_ALL
);
verification_mode
=
SSL_VERIFY_NONE
;
if
(
certreq
==
PY_SSL_CERT_OPTIONAL
)
verification_mode
=
SSL_VERIFY_PEER
;
else
if
(
certreq
==
PY_SSL_CERT_REQUIRED
)
verification_mode
=
(
SSL_VERIFY_PEER
|
SSL_VERIFY_FAIL_IF_NO_PEER_CERT
);
SSL_CTX_set_verify
(
self
->
ctx
,
verification_mode
,
NULL
);
/* set verify lvl */
PySSL_BEGIN_ALLOW_THREADS
self
->
ssl
=
SSL_new
(
self
->
ctx
);
/* New ssl struct */
self
->
ssl
=
SSL_new
(
ctx
);
PySSL_END_ALLOW_THREADS
SSL_set_fd
(
self
->
ssl
,
Sock
->
sock_fd
);
/* Set the socket for SSL */
SSL_set_fd
(
self
->
ssl
,
sock
->
sock_fd
);
#ifdef SSL_MODE_AUTO_RETRY
SSL_set_mode
(
self
->
ssl
,
SSL_MODE_AUTO_RETRY
);
#endif
...
...
@@ -385,8 +293,7 @@ newPySSLObject(PySocketSockObject *Sock, char *key_file, char *cert_file,
/* If the socket is in non-blocking mode or timeout mode, set the BIO
* to non-blocking mode (blocking is the default)
*/
if
(
Sock
->
sock_timeout
>=
0
.
0
)
{
/* Set both the read and write BIO's to non-blocking mode */
if
(
sock
->
sock_timeout
>=
0
.
0
)
{
BIO_set_nbio
(
SSL_get_rbio
(
self
->
ssl
),
1
);
BIO_set_nbio
(
SSL_get_wbio
(
self
->
ssl
),
1
);
}
...
...
@@ -398,57 +305,13 @@ newPySSLObject(PySocketSockObject *Sock, char *key_file, char *cert_file,
SSL_set_accept_state
(
self
->
ssl
);
PySSL_END_ALLOW_THREADS
self
->
Socket
=
PyWeakref_NewRef
((
PyObject
*
)
Sock
,
Py_None
);
self
->
Socket
=
PyWeakref_NewRef
((
PyObject
*
)
sock
,
NULL
);
return
self
;
fail:
if
(
errstr
)
PyErr_SetString
(
PySSLErrorObject
,
errstr
);
Py_DECREF
(
self
);
return
NULL
;
}
static
PyObject
*
PySSL_sslwrap
(
PyObject
*
self
,
PyObject
*
args
)
{
PySocketSockObject
*
Sock
;
int
server_side
=
0
;
int
verification_mode
=
PY_SSL_CERT_NONE
;
int
protocol
=
PY_SSL_VERSION_SSL23
;
char
*
key_file
=
NULL
;
char
*
cert_file
=
NULL
;
char
*
cacerts_file
=
NULL
;
char
*
ciphers
=
NULL
;
if
(
!
PyArg_ParseTuple
(
args
,
"O!i|zziizz:sslwrap"
,
PySocketModule
.
Sock_Type
,
&
Sock
,
&
server_side
,
&
key_file
,
&
cert_file
,
&
verification_mode
,
&
protocol
,
&
cacerts_file
,
&
ciphers
))
return
NULL
;
/*
fprintf(stderr,
"server_side is %d, keyfile %p, certfile %p, verify_mode %d, "
"protocol %d, certs %p\n",
server_side, key_file, cert_file, verification_mode,
protocol, cacerts_file);
*/
return
(
PyObject
*
)
newPySSLObject
(
Sock
,
key_file
,
cert_file
,
server_side
,
verification_mode
,
protocol
,
cacerts_file
,
ciphers
);
}
PyDoc_STRVAR
(
ssl_doc
,
"sslwrap(socket, server_side, [keyfile, certfile, certs_mode, protocol,
\n
"
" cacertsfile, ciphers]) -> sslobject"
);
/* SSL object methods */
static
PyObject
*
PySSL_SSLdo_handshake
(
PySSL
Objec
t
*
self
)
static
PyObject
*
PySSL_SSLdo_handshake
(
PySSL
Socke
t
*
self
)
{
int
ret
;
int
err
;
...
...
@@ -986,7 +849,7 @@ PySSL_test_decode_certificate (PyObject *mod, PyObject *args) {
static
PyObject
*
PySSL_peercert
(
PySSL
Objec
t
*
self
,
PyObject
*
args
)
PySSL_peercert
(
PySSL
Socke
t
*
self
,
PyObject
*
args
)
{
PyObject
*
retval
=
NULL
;
int
len
;
...
...
@@ -1017,8 +880,7 @@ PySSL_peercert(PySSLObject *self, PyObject *args)
return
retval
;
}
else
{
verification
=
SSL_CTX_get_verify_mode
(
self
->
ctx
);
verification
=
SSL_CTX_get_verify_mode
(
SSL_get_SSL_CTX
(
self
->
ssl
));
if
((
verification
&
SSL_VERIFY_PEER
)
==
0
)
return
PyDict_New
();
else
...
...
@@ -1038,7 +900,7 @@ If the optional argument is True, returns a DER-encoded copy of the\n\
peer certificate, or None if no certificate was provided. This will
\n
\
return the certificate even if it wasn't validated."
);
static
PyObject
*
PySSL_cipher
(
PySSL
Objec
t
*
self
)
{
static
PyObject
*
PySSL_cipher
(
PySSL
Socke
t
*
self
)
{
PyObject
*
retval
,
*
v
;
SSL_CIPHER
*
current
;
...
...
@@ -1084,14 +946,12 @@ static PyObject *PySSL_cipher (PySSLObject *self) {
return
NULL
;
}
static
void
PySSL_dealloc
(
PySSL
Objec
t
*
self
)
static
void
PySSL_dealloc
(
PySSL
Socke
t
*
self
)
{
if
(
self
->
peer_cert
)
/* Possible not to have one? */
X509_free
(
self
->
peer_cert
);
if
(
self
->
ssl
)
SSL_free
(
self
->
ssl
);
if
(
self
->
ctx
)
SSL_CTX_free
(
self
->
ctx
);
Py_XDECREF
(
self
->
Socket
);
PyObject_Del
(
self
);
}
...
...
@@ -1166,7 +1026,7 @@ normal_return:
return
rc
==
0
?
SOCKET_HAS_TIMED_OUT
:
SOCKET_OPERATION_OK
;
}
static
PyObject
*
PySSL_SSLwrite
(
PySSL
Objec
t
*
self
,
PyObject
*
args
)
static
PyObject
*
PySSL_SSLwrite
(
PySSL
Socke
t
*
self
,
PyObject
*
args
)
{
Py_buffer
buf
;
int
len
;
...
...
@@ -1250,7 +1110,7 @@ PyDoc_STRVAR(PySSL_SSLwrite_doc,
Writes the string s into the SSL object. Returns the number
\n
\
of bytes written."
);
static
PyObject
*
PySSL_SSLpending
(
PySSL
Objec
t
*
self
)
static
PyObject
*
PySSL_SSLpending
(
PySSL
Socke
t
*
self
)
{
int
count
=
0
;
...
...
@@ -1269,7 +1129,7 @@ PyDoc_STRVAR(PySSL_SSLpending_doc,
Returns the number of already decrypted bytes available for read,
\n
\
pending on the connection.
\n
"
);
static
PyObject
*
PySSL_SSLread
(
PySSL
Objec
t
*
self
,
PyObject
*
args
)
static
PyObject
*
PySSL_SSLread
(
PySSL
Socke
t
*
self
,
PyObject
*
args
)
{
PyObject
*
dest
=
NULL
;
Py_buffer
buf
;
...
...
@@ -1392,7 +1252,7 @@ PyDoc_STRVAR(PySSL_SSLread_doc,
\n
\
Read up to len bytes from the SSL socket."
);
static
PyObject
*
PySSL_SSLshutdown
(
PySSL
Objec
t
*
self
)
static
PyObject
*
PySSL_SSLshutdown
(
PySSL
Socke
t
*
self
)
{
int
err
,
ssl_err
,
sockstate
,
nonblocking
;
int
zeros
=
0
;
...
...
@@ -1497,10 +1357,10 @@ static PyMethodDef PySSLMethods[] = {
{
NULL
,
NULL
}
};
static
PyTypeObject
PySSL_Type
=
{
static
PyTypeObject
PySSL
Socket
_Type
=
{
PyVarObject_HEAD_INIT
(
NULL
,
0
)
"
ssl.SSLContext"
,
/*tp_name*/
sizeof
(
PySSL
Objec
t
),
/*tp_basicsize*/
"
_ssl._SSLSocket"
,
/*tp_name*/
sizeof
(
PySSL
Socke
t
),
/*tp_basicsize*/
0
,
/*tp_itemsize*/
/* methods */
(
destructor
)
PySSL_dealloc
,
/*tp_dealloc*/
...
...
@@ -1529,6 +1389,306 @@ static PyTypeObject PySSL_Type = {
PySSLMethods
,
/*tp_methods*/
};
/*
* _SSLContext objects
*/
static
PyObject
*
context_new
(
PyTypeObject
*
type
,
PyObject
*
args
,
PyObject
*
kwds
)
{
char
*
kwlist
[]
=
{
"protocol"
,
NULL
};
PySSLContext
*
self
;
int
proto_version
=
PY_SSL_VERSION_SSL23
;
SSL_CTX
*
ctx
=
NULL
;
if
(
!
PyArg_ParseTupleAndKeywords
(
args
,
kwds
,
"i:_SSLContext"
,
kwlist
,
&
proto_version
))
return
NULL
;
PySSL_BEGIN_ALLOW_THREADS
if
(
proto_version
==
PY_SSL_VERSION_TLS1
)
ctx
=
SSL_CTX_new
(
TLSv1_method
());
else
if
(
proto_version
==
PY_SSL_VERSION_SSL3
)
ctx
=
SSL_CTX_new
(
SSLv3_method
());
else
if
(
proto_version
==
PY_SSL_VERSION_SSL2
)
ctx
=
SSL_CTX_new
(
SSLv2_method
());
else
if
(
proto_version
==
PY_SSL_VERSION_SSL23
)
ctx
=
SSL_CTX_new
(
SSLv23_method
());
else
proto_version
=
-
1
;
PySSL_END_ALLOW_THREADS
if
(
proto_version
==
-
1
)
{
PyErr_SetString
(
PyExc_ValueError
,
"invalid protocol version"
);
return
NULL
;
}
if
(
ctx
==
NULL
)
{
PyErr_SetString
(
PySSLErrorObject
,
"failed to allocate SSL context"
);
return
NULL
;
}
assert
(
type
!=
NULL
&&
type
->
tp_alloc
!=
NULL
);
self
=
(
PySSLContext
*
)
type
->
tp_alloc
(
type
,
0
);
if
(
self
==
NULL
)
{
SSL_CTX_free
(
ctx
);
return
NULL
;
}
self
->
ctx
=
ctx
;
/* Defaults */
SSL_CTX_set_verify
(
self
->
ctx
,
SSL_VERIFY_NONE
,
NULL
);
SSL_CTX_set_options
(
self
->
ctx
,
SSL_OP_ALL
);
return
(
PyObject
*
)
self
;
}
static
void
context_dealloc
(
PySSLContext
*
self
)
{
SSL_CTX_free
(
self
->
ctx
);
Py_TYPE
(
self
)
->
tp_free
(
self
);
}
static
PyObject
*
set_ciphers
(
PySSLContext
*
self
,
PyObject
*
args
)
{
int
ret
;
const
char
*
cipherlist
;
if
(
!
PyArg_ParseTuple
(
args
,
"s:set_ciphers"
,
&
cipherlist
))
return
NULL
;
ret
=
SSL_CTX_set_cipher_list
(
self
->
ctx
,
cipherlist
);
if
(
ret
==
0
)
{
PyErr_SetString
(
PySSLErrorObject
,
"No cipher can be selected."
);
return
NULL
;
}
Py_RETURN_NONE
;
}
static
PyObject
*
get_verify_mode
(
PySSLContext
*
self
,
void
*
c
)
{
switch
(
SSL_CTX_get_verify_mode
(
self
->
ctx
))
{
case
SSL_VERIFY_NONE
:
return
PyLong_FromLong
(
PY_SSL_CERT_NONE
);
case
SSL_VERIFY_PEER
:
return
PyLong_FromLong
(
PY_SSL_CERT_OPTIONAL
);
case
SSL_VERIFY_PEER
|
SSL_VERIFY_FAIL_IF_NO_PEER_CERT
:
return
PyLong_FromLong
(
PY_SSL_CERT_REQUIRED
);
}
PyErr_SetString
(
PySSLErrorObject
,
"invalid return value from SSL_CTX_get_verify_mode"
);
return
NULL
;
}
static
int
set_verify_mode
(
PySSLContext
*
self
,
PyObject
*
arg
,
void
*
c
)
{
int
n
,
mode
;
if
(
!
PyArg_Parse
(
arg
,
"i"
,
&
n
))
return
-
1
;
if
(
n
==
PY_SSL_CERT_NONE
)
mode
=
SSL_VERIFY_NONE
;
else
if
(
n
==
PY_SSL_CERT_OPTIONAL
)
mode
=
SSL_VERIFY_PEER
;
else
if
(
n
==
PY_SSL_CERT_REQUIRED
)
mode
=
SSL_VERIFY_PEER
|
SSL_VERIFY_FAIL_IF_NO_PEER_CERT
;
else
{
PyErr_SetString
(
PyExc_ValueError
,
"invalid value for verify_mode"
);
return
-
1
;
}
SSL_CTX_set_verify
(
self
->
ctx
,
mode
,
NULL
);
return
0
;
}
static
PyObject
*
load_cert_chain
(
PySSLContext
*
self
,
PyObject
*
args
,
PyObject
*
kwds
)
{
char
*
kwlist
[]
=
{
"certfile"
,
"keyfile"
,
NULL
};
PyObject
*
certfile
,
*
keyfile
=
NULL
;
PyObject
*
certfile_bytes
=
NULL
,
*
keyfile_bytes
=
NULL
;
int
r
;
if
(
!
PyArg_ParseTupleAndKeywords
(
args
,
kwds
,
"O|O:load_cert_chain"
,
kwlist
,
&
certfile
,
&
keyfile
))
return
NULL
;
if
(
keyfile
==
Py_None
)
keyfile
=
NULL
;
if
(
!
PyUnicode_FSConverter
(
certfile
,
&
certfile_bytes
))
{
PyErr_SetString
(
PyExc_TypeError
,
"certfile should be a valid filesystem path"
);
return
NULL
;
}
if
(
keyfile
&&
!
PyUnicode_FSConverter
(
keyfile
,
&
keyfile_bytes
))
{
PyErr_SetString
(
PyExc_TypeError
,
"keyfile should be a valid filesystem path"
);
goto
error
;
}
PySSL_BEGIN_ALLOW_THREADS
r
=
SSL_CTX_use_certificate_chain_file
(
self
->
ctx
,
PyBytes_AS_STRING
(
certfile_bytes
));
PySSL_END_ALLOW_THREADS
if
(
r
!=
1
)
{
_setSSLError
(
NULL
,
0
,
__FILE__
,
__LINE__
);
goto
error
;
}
PySSL_BEGIN_ALLOW_THREADS
r
=
SSL_CTX_use_RSAPrivateKey_file
(
self
->
ctx
,
PyBytes_AS_STRING
(
keyfile
?
keyfile_bytes
:
certfile_bytes
),
SSL_FILETYPE_PEM
);
PySSL_END_ALLOW_THREADS
Py_XDECREF
(
keyfile_bytes
);
Py_XDECREF
(
certfile_bytes
);
if
(
r
!=
1
)
{
_setSSLError
(
NULL
,
0
,
__FILE__
,
__LINE__
);
return
NULL
;
}
PySSL_BEGIN_ALLOW_THREADS
r
=
SSL_CTX_check_private_key
(
self
->
ctx
);
PySSL_END_ALLOW_THREADS
if
(
r
!=
1
)
{
_setSSLError
(
NULL
,
0
,
__FILE__
,
__LINE__
);
return
NULL
;
}
Py_RETURN_NONE
;
error:
Py_XDECREF
(
keyfile_bytes
);
Py_XDECREF
(
certfile_bytes
);
return
NULL
;
}
static
PyObject
*
load_verify_locations
(
PySSLContext
*
self
,
PyObject
*
args
,
PyObject
*
kwds
)
{
char
*
kwlist
[]
=
{
"cafile"
,
"capath"
,
NULL
};
PyObject
*
cafile
=
NULL
,
*
capath
=
NULL
;
PyObject
*
cafile_bytes
=
NULL
,
*
capath_bytes
=
NULL
;
const
char
*
cafile_buf
=
NULL
,
*
capath_buf
=
NULL
;
int
r
;
if
(
!
PyArg_ParseTupleAndKeywords
(
args
,
kwds
,
"|OO:load_verify_locations"
,
kwlist
,
&
cafile
,
&
capath
))
return
NULL
;
if
(
cafile
==
Py_None
)
cafile
=
NULL
;
if
(
capath
==
Py_None
)
capath
=
NULL
;
if
(
cafile
==
NULL
&&
capath
==
NULL
)
{
PyErr_SetString
(
PyExc_TypeError
,
"cafile and capath cannot be both omitted"
);
return
NULL
;
}
if
(
cafile
&&
!
PyUnicode_FSConverter
(
cafile
,
&
cafile_bytes
))
{
PyErr_SetString
(
PyExc_TypeError
,
"cafile should be a valid filesystem path"
);
return
NULL
;
}
if
(
capath
&&
!
PyUnicode_FSConverter
(
capath
,
&
capath_bytes
))
{
Py_DECREF
(
cafile_bytes
);
PyErr_SetString
(
PyExc_TypeError
,
"capath should be a valid filesystem path"
);
return
NULL
;
}
if
(
cafile
)
cafile_buf
=
PyBytes_AS_STRING
(
cafile_bytes
);
if
(
capath
)
capath_buf
=
PyBytes_AS_STRING
(
capath_bytes
);
PySSL_BEGIN_ALLOW_THREADS
r
=
SSL_CTX_load_verify_locations
(
self
->
ctx
,
cafile_buf
,
capath_buf
);
PySSL_END_ALLOW_THREADS
Py_XDECREF
(
cafile_bytes
);
Py_XDECREF
(
capath_bytes
);
if
(
r
!=
1
)
{
_setSSLError
(
NULL
,
0
,
__FILE__
,
__LINE__
);
return
NULL
;
}
Py_RETURN_NONE
;
}
static
PyObject
*
context_wrap_socket
(
PySSLContext
*
self
,
PyObject
*
args
,
PyObject
*
kwds
)
{
char
*
kwlist
[]
=
{
"sock"
,
"server_side"
,
NULL
};
PySocketSockObject
*
sock
;
int
server_side
=
0
;
if
(
!
PyArg_ParseTupleAndKeywords
(
args
,
kwds
,
"O!i:_wrap_socket"
,
kwlist
,
PySocketModule
.
Sock_Type
,
&
sock
,
&
server_side
))
return
NULL
;
return
(
PyObject
*
)
newPySSLSocket
(
self
->
ctx
,
sock
,
server_side
);
}
static
PyGetSetDef
context_getsetlist
[]
=
{
{
"verify_mode"
,
(
getter
)
get_verify_mode
,
(
setter
)
set_verify_mode
,
NULL
},
{
NULL
},
/* sentinel */
};
static
struct
PyMethodDef
context_methods
[]
=
{
{
"_wrap_socket"
,
(
PyCFunction
)
context_wrap_socket
,
METH_VARARGS
|
METH_KEYWORDS
,
NULL
},
{
"set_ciphers"
,
(
PyCFunction
)
set_ciphers
,
METH_VARARGS
,
NULL
},
{
"load_cert_chain"
,
(
PyCFunction
)
load_cert_chain
,
METH_VARARGS
|
METH_KEYWORDS
,
NULL
},
{
"load_verify_locations"
,
(
PyCFunction
)
load_verify_locations
,
METH_VARARGS
|
METH_KEYWORDS
,
NULL
},
{
NULL
,
NULL
}
/* sentinel */
};
static
PyTypeObject
PySSLContext_Type
=
{
PyVarObject_HEAD_INIT
(
NULL
,
0
)
"_ssl._SSLContext"
,
/*tp_name*/
sizeof
(
PySSLContext
),
/*tp_basicsize*/
0
,
/*tp_itemsize*/
(
destructor
)
context_dealloc
,
/*tp_dealloc*/
0
,
/*tp_print*/
0
,
/*tp_getattr*/
0
,
/*tp_setattr*/
0
,
/*tp_reserved*/
0
,
/*tp_repr*/
0
,
/*tp_as_number*/
0
,
/*tp_as_sequence*/
0
,
/*tp_as_mapping*/
0
,
/*tp_hash*/
0
,
/*tp_call*/
0
,
/*tp_str*/
0
,
/*tp_getattro*/
0
,
/*tp_setattro*/
0
,
/*tp_as_buffer*/
Py_TPFLAGS_DEFAULT
|
Py_TPFLAGS_BASETYPE
,
/*tp_flags*/
0
,
/*tp_doc*/
0
,
/*tp_traverse*/
0
,
/*tp_clear*/
0
,
/*tp_richcompare*/
0
,
/*tp_weaklistoffset*/
0
,
/*tp_iter*/
0
,
/*tp_iternext*/
context_methods
,
/*tp_methods*/
0
,
/*tp_members*/
context_getsetlist
,
/*tp_getset*/
0
,
/*tp_base*/
0
,
/*tp_dict*/
0
,
/*tp_descr_get*/
0
,
/*tp_descr_set*/
0
,
/*tp_dictoffset*/
0
,
/*tp_init*/
0
,
/*tp_alloc*/
context_new
,
/*tp_new*/
};
#ifdef HAVE_OPENSSL_RAND
/* helper routines for seeding the SSL PRNG */
...
...
@@ -1598,8 +1758,6 @@ fails or if it does provide enough data to seed PRNG.");
/* List of functions exported by this module. */
static
PyMethodDef
PySSL_methods
[]
=
{
{
"sslwrap"
,
PySSL_sslwrap
,
METH_VARARGS
,
ssl_doc
},
{
"_test_decode_cert"
,
PySSL_test_decode_certificate
,
METH_VARARGS
},
#ifdef HAVE_OPENSSL_RAND
...
...
@@ -1708,7 +1866,9 @@ PyInit__ssl(void)
unsigned
int
major
,
minor
,
fix
,
patch
,
status
;
PySocketModule_APIObject
*
socket_api
;
if
(
PyType_Ready
(
&
PySSL_Type
)
<
0
)
if
(
PyType_Ready
(
&
PySSLContext_Type
)
<
0
)
return
NULL
;
if
(
PyType_Ready
(
&
PySSLSocket_Type
)
<
0
)
return
NULL
;
m
=
PyModule_Create
(
&
_sslmodule
);
...
...
@@ -1741,8 +1901,11 @@ PyInit__ssl(void)
return
NULL
;
if
(
PyDict_SetItemString
(
d
,
"SSLError"
,
PySSLErrorObject
)
!=
0
)
return
NULL
;
if
(
PyDict_SetItemString
(
d
,
"SSLType"
,
(
PyObject
*
)
&
PySSL_Type
)
!=
0
)
if
(
PyDict_SetItemString
(
d
,
"_SSLContext"
,
(
PyObject
*
)
&
PySSLContext_Type
)
!=
0
)
return
NULL
;
if
(
PyDict_SetItemString
(
d
,
"_SSLSocket"
,
(
PyObject
*
)
&
PySSLSocket_Type
)
!=
0
)
return
NULL
;
PyModule_AddIntConstant
(
m
,
"SSL_ERROR_ZERO_RETURN"
,
PY_SSL_ERROR_ZERO_RETURN
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment