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
c2fc7c4f
Commit
c2fc7c4f
authored
Sep 05, 2016
by
Christian Heimes
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Issue #26470: Port ssl and hashlib module to OpenSSL 1.1.0.
parent
34458277
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
342 additions
and
135 deletions
+342
-135
Doc/library/ssl.rst
Doc/library/ssl.rst
+49
-2
Lib/ssl.py
Lib/ssl.py
+10
-6
Lib/test/test_ssl.py
Lib/test/test_ssl.py
+40
-26
Misc/NEWS
Misc/NEWS
+2
-0
Modules/_hashopenssl.c
Modules/_hashopenssl.c
+110
-60
Modules/_ssl.c
Modules/_ssl.c
+131
-41
No files found.
Doc/library/ssl.rst
View file @
c2fc7c4f
...
...
@@ -322,6 +322,16 @@ purposes.
Random generation
^^^^^^^^^^^^^^^^^
.. deprecated::
2.7.13 OpenSSL has deprecated :func:`ssl.RAND_pseudo_bytes`, use
:func:`ssl.RAND_bytes` instead.
.. deprecated::
2.7.13 OpenSSL has deprecated :func:`ssl.RAND_pseudo_bytes`, use
:func:`ssl.RAND_bytes` instead.
.. function:: RAND_status()
Return ``True`` if the SSL pseudo-random number generator has been seeded
...
...
@@ -340,7 +350,7 @@ Random generation
See http://egd.sourceforge.net/ or http://prngd.sourceforge.net/ for sources
of entropy-gathering daemons.
Availability: not available with LibreSSL
.
Availability: not available with LibreSSL
and OpenSSL > 1.1.0
.. function:: RAND_add(bytes, entropy)
...
...
@@ -444,6 +454,9 @@ Certificate handling
* :attr:`openssl_capath_env` - OpenSSL's environment key that points to a capath,
* :attr:`openssl_capath` - hard coded path to a capath directory
Availability: LibreSSL ignores the environment vars
:attr:`openssl_cafile_env` and :attr:`openssl_capath_env`
.. versionadded:: 2.7.9
.. function:: enum_certificates(store_name)
...
...
@@ -561,11 +574,19 @@ Constants
.. versionadded:: 2.7.10
.. data:: PROTOCOL_
SSLv23
.. data:: PROTOCOL_
TLS
Selects the highest protocol version that both the client and server support.
Despite the name, this option can select "TLS" protocols as well as "SSL".
.. versionadded:: 2.7.13
.. data:: PROTOCOL_SSLv23
Alias for ``PROTOCOL_TLS``.
.. deprecated:: 2.7.13 Use ``PROTOCOL_TLS`` instead.
.. data:: PROTOCOL_SSLv2
Selects SSL version 2 as the channel encryption protocol.
...
...
@@ -577,6 +598,8 @@ Constants
SSL version 2 is insecure. Its use is highly discouraged.
.. deprecated:: 2.7.13 OpenSSL has removed support for SSLv2.
.. data:: PROTOCOL_SSLv3
Selects SSL version 3 as the channel encryption protocol.
...
...
@@ -588,10 +611,20 @@ Constants
SSL version 3 is insecure. Its use is highly discouraged.
.. deprecated:: 2.7.13
OpenSSL has deprecated all version specific protocols. Use the default
protocol with flags like ``OP_NO_SSLv3`` instead.
.. data:: PROTOCOL_TLSv1
Selects TLS version 1.0 as the channel encryption protocol.
.. deprecated:: 2.7.13
OpenSSL has deprecated all version specific protocols. Use the default
protocol with flags like ``OP_NO_SSLv3`` instead.
.. data:: PROTOCOL_TLSv1_1
Selects TLS version 1.1 as the channel encryption protocol.
...
...
@@ -599,6 +632,11 @@ Constants
.. versionadded:: 2.7.9
.. deprecated:: 2.7.13
OpenSSL has deprecated all version specific protocols. Use the default
protocol with flags like ``OP_NO_SSLv3`` instead.
.. data:: PROTOCOL_TLSv1_2
Selects TLS version 1.2 as the channel encryption protocol. This is the
...
...
@@ -607,6 +645,12 @@ Constants
.. versionadded:: 2.7.9
.. deprecated:: 2.7.13
OpenSSL has deprecated all version specific protocols. Use the default
protocol with flags like ``OP_NO_SSLv3`` instead.
.. data:: OP_ALL
Enables workarounds for various bugs present in other SSL implementations.
...
...
@@ -1112,6 +1156,9 @@ to speed up repeated connections from the same clients.
This method will raise :exc:`NotImplementedError` if :data:`HAS_ALPN` is
False.
OpenSSL 1.1.0+ will abort the handshake and raise :exc:`SSLError` when
both sides support ALPN but cannot agree on a protocol.
.. versionadded:: 2.7.10
.. method:: SSLContext.set_npn_protocols(protocols)
...
...
Lib/ssl.py
View file @
c2fc7c4f
...
...
@@ -51,6 +51,7 @@ The following constants identify various SSL protocol variants:
PROTOCOL_SSLv2
PROTOCOL_SSLv3
PROTOCOL_SSLv23
PROTOCOL_TLS
PROTOCOL_TLSv1
PROTOCOL_TLSv1_1
PROTOCOL_TLSv1_2
...
...
@@ -126,7 +127,10 @@ from _ssl import HAS_SNI, HAS_ECDH, HAS_NPN, HAS_ALPN
from
_ssl
import
_OPENSSL_API_VERSION
_PROTOCOL_NAMES
=
{
value
:
name
for
name
,
value
in
globals
().
items
()
if
name
.
startswith
(
'PROTOCOL_'
)}
_PROTOCOL_NAMES
=
{
value
:
name
for
name
,
value
in
globals
().
items
()
if
name
.
startswith
(
'PROTOCOL_'
)
and
name
!=
'PROTOCOL_SSLv23'
}
PROTOCOL_SSLv23
=
PROTOCOL_TLS
try
:
_SSLv2_IF_EXISTS
=
PROTOCOL_SSLv2
...
...
@@ -408,7 +412,7 @@ def create_default_context(purpose=Purpose.SERVER_AUTH, cafile=None,
if not isinstance(purpose, _ASN1Object):
raise TypeError(purpose)
context = SSLContext(PROTOCOL_
SSLv23
)
context = SSLContext(PROTOCOL_
TLS
)
# SSLv2 considered harmful.
context.options |= OP_NO_SSLv2
...
...
@@ -445,7 +449,7 @@ def create_default_context(purpose=Purpose.SERVER_AUTH, cafile=None,
context
.
load_default_certs
(
purpose
)
return
context
def
_create_unverified_context
(
protocol
=
PROTOCOL_
SSLv23
,
cert_reqs
=
None
,
def
_create_unverified_context
(
protocol
=
PROTOCOL_
TLS
,
cert_reqs
=
None
,
check_hostname
=
False
,
purpose
=
Purpose
.
SERVER_AUTH
,
certfile
=
None
,
keyfile
=
None
,
cafile
=
None
,
capath
=
None
,
cadata
=
None
):
...
...
@@ -518,7 +522,7 @@ class SSLSocket(socket):
def
__init__
(
self
,
sock
=
None
,
keyfile
=
None
,
certfile
=
None
,
server_side
=
False
,
cert_reqs
=
CERT_NONE
,
ssl_version
=
PROTOCOL_
SSLv23
,
ca_certs
=
None
,
ssl_version
=
PROTOCOL_
TLS
,
ca_certs
=
None
,
do_handshake_on_connect
=
True
,
family
=
AF_INET
,
type
=
SOCK_STREAM
,
proto
=
0
,
fileno
=
None
,
suppress_ragged_eofs
=
True
,
npn_protocols
=
None
,
ciphers
=
None
,
...
...
@@ -920,7 +924,7 @@ class SSLSocket(socket):
def
wrap_socket
(
sock
,
keyfile
=
None
,
certfile
=
None
,
server_side
=
False
,
cert_reqs
=
CERT_NONE
,
ssl_version
=
PROTOCOL_
SSLv23
,
ca_certs
=
None
,
ssl_version
=
PROTOCOL_
TLS
,
ca_certs
=
None
,
do_handshake_on_connect
=
True
,
suppress_ragged_eofs
=
True
,
ciphers
=
None
):
...
...
@@ -989,7 +993,7 @@ def PEM_cert_to_DER_cert(pem_cert_string):
d
=
pem_cert_string
.
strip
()[
len
(
PEM_HEADER
):
-
len
(
PEM_FOOTER
)]
return
base64
.
decodestring
(
d
.
encode
(
'ASCII'
,
'strict'
))
def
get_server_certificate
(
addr
,
ssl_version
=
PROTOCOL_
SSLv23
,
ca_certs
=
None
):
def
get_server_certificate
(
addr
,
ssl_version
=
PROTOCOL_
TLS
,
ca_certs
=
None
):
"""Retrieve the certificate from the server at the specified address,
and return it as a PEM-encoded string.
If 'ca_certs' is specified, validate the server cert against it.
...
...
Lib/test/test_ssl.py
View file @
c2fc7c4f
...
...
@@ -26,6 +26,9 @@ ssl = support.import_module("ssl")
PROTOCOLS
=
sorted
(
ssl
.
_PROTOCOL_NAMES
)
HOST
=
support
.
HOST
IS_LIBRESSL
=
ssl
.
OPENSSL_VERSION
.
startswith
(
'LibreSSL'
)
IS_OPENSSL_1_1
=
not
IS_LIBRESSL
and
ssl
.
OPENSSL_VERSION_INFO
>=
(
1
,
1
,
0
)
def
data_file
(
*
name
):
return
os
.
path
.
join
(
os
.
path
.
dirname
(
__file__
),
*
name
)
...
...
@@ -164,7 +167,6 @@ class BasicSocketTests(unittest.TestCase):
self
.
assertIn
(
ssl
.
HAS_SNI
,
{
True
,
False
})
self
.
assertIn
(
ssl
.
HAS_ECDH
,
{
True
,
False
})
def
test_random
(
self
):
v
=
ssl
.
RAND_status
()
if
support
.
verbose
:
...
...
@@ -281,9 +283,9 @@ class BasicSocketTests(unittest.TestCase):
self
.
assertGreaterEqual
(
status
,
0
)
self
.
assertLessEqual
(
status
,
15
)
# Version string as returned by {Open,Libre}SSL, the format might change
if
"LibreSSL"
in
s
:
self
.
assertTrue
(
s
.
startswith
(
"LibreSSL {:d}
.{:d}"
.
format
(
major
,
min
or
)),
(
s
,
t
))
if
IS_LIBRESSL
:
self
.
assertTrue
(
s
.
startswith
(
"LibreSSL {:d}
"
.
format
(
maj
or
)),
(
s
,
t
,
hex
(
n
)
))
else
:
self
.
assertTrue
(
s
.
startswith
(
"OpenSSL {:d}.{:d}.{:d}"
.
format
(
major
,
minor
,
fix
)),
(
s
,
t
))
...
...
@@ -742,15 +744,15 @@ class ContextTests(unittest.TestCase):
def
test_options
(
self
):
ctx
=
ssl
.
SSLContext
(
ssl
.
PROTOCOL_TLSv1
)
# OP_ALL | OP_NO_SSLv2 | OP_NO_SSLv3 is the default value
self
.
assertEqual
(
ssl
.
OP_ALL
|
ssl
.
OP_NO_SSLv2
|
ssl
.
OP_NO_SSLv3
,
ctx
.
options
)
default
=
(
ssl
.
OP_ALL
|
ssl
.
OP_NO_SSLv2
|
ssl
.
OP_NO_SSLv3
)
if
not
IS_LIBRESSL
and
ssl
.
OPENSSL_VERSION_INFO
>=
(
1
,
1
,
0
):
default
|=
ssl
.
OP_NO_COMPRESSION
self
.
assertEqual
(
default
,
ctx
.
options
)
ctx
.
options
|=
ssl
.
OP_NO_TLSv1
self
.
assertEqual
(
ssl
.
OP_ALL
|
ssl
.
OP_NO_SSLv2
|
ssl
.
OP_NO_SSLv3
|
ssl
.
OP_NO_TLSv1
,
ctx
.
options
)
self
.
assertEqual
(
default
|
ssl
.
OP_NO_TLSv1
,
ctx
.
options
)
if
can_clear_options
():
ctx
.
options
=
(
ctx
.
options
&
~
ssl
.
OP_NO_SSLv2
)
|
ssl
.
OP_NO_TLSv1
self
.
assertEqual
(
ssl
.
OP_ALL
|
ssl
.
OP_NO_TLSv1
|
ssl
.
OP_NO_SSLv3
,
ctx
.
options
)
ctx
.
options
=
(
ctx
.
options
&
~
ssl
.
OP_NO_TLSv1
)
self
.
assertEqual
(
default
,
ctx
.
options
)
ctx
.
options
=
0
self
.
assertEqual
(
0
,
ctx
.
options
)
else
:
...
...
@@ -1088,6 +1090,7 @@ class ContextTests(unittest.TestCase):
self
.
assertRaises
(
TypeError
,
ctx
.
load_default_certs
,
'SERVER_AUTH'
)
@
unittest
.
skipIf
(
sys
.
platform
==
"win32"
,
"not-Windows specific"
)
@
unittest
.
skipIf
(
IS_LIBRESSL
,
"LibreSSL doesn't support env vars"
)
def
test_load_default_certs_env
(
self
):
ctx
=
ssl
.
SSLContext
(
ssl
.
PROTOCOL_TLSv1
)
with
support
.
EnvironmentVarGuard
()
as
env
:
...
...
@@ -1534,7 +1537,6 @@ class NetworkedTests(unittest.TestCase):
sys
.
stdout
.
write
(
"%s
\
n
"
%
x
)
else
:
self
.
fail
(
"Got server certificate %s for %s:%s!"
%
(
pem
,
host
,
port
))
pem
=
ssl
.
get_server_certificate
((
host
,
port
),
ca_certs
=
cert
)
if
not
pem
:
...
...
@@ -2783,7 +2785,7 @@ else:
with
closing
(
context
.
wrap_socket
(
socket
.
socket
()))
as
s
:
self
.
assertIs
(
s
.
version
(),
None
)
s
.
connect
((
HOST
,
server
.
port
))
self
.
assertEqual
(
s
.
version
(),
"TLSv1"
)
self
.
assertEqual
(
s
.
version
(),
'TLSv1'
)
self
.
assertIs
(
s
.
version
(),
None
)
@
unittest
.
skipUnless
(
ssl
.
HAS_ECDH
,
"test requires ECDH-enabled OpenSSL"
)
...
...
@@ -2925,24 +2927,36 @@ else:
([
'http/3.0'
,
'http/4.0'
],
None
)
]
for
client_protocols
,
expected
in
protocol_tests
:
server_context
=
ssl
.
SSLContext
(
ssl
.
PROTOCOL_TLSv1
)
server_context
=
ssl
.
SSLContext
(
ssl
.
PROTOCOL_TLSv1
_2
)
server_context
.
load_cert_chain
(
CERTFILE
)
server_context
.
set_alpn_protocols
(
server_protocols
)
client_context
=
ssl
.
SSLContext
(
ssl
.
PROTOCOL_TLSv1
)
client_context
=
ssl
.
SSLContext
(
ssl
.
PROTOCOL_TLSv1
_2
)
client_context
.
load_cert_chain
(
CERTFILE
)
client_context
.
set_alpn_protocols
(
client_protocols
)
stats
=
server_params_test
(
client_context
,
server_context
,
chatty
=
True
,
connectionchatty
=
True
)
msg
=
"failed trying %s (s) and %s (c).
\
n
"
\
"was expecting %s, but got %%s from the %%s"
\
%
(
str
(
server_protocols
),
str
(
client_protocols
),
str
(
expected
))
client_result
=
stats
[
'client_alpn_protocol'
]
self
.
assertEqual
(
client_result
,
expected
,
msg
%
(
client_result
,
"client"
))
server_result
=
stats
[
'server_alpn_protocols'
][
-
1
]
\
if
len
(
stats
[
'server_alpn_protocols'
])
else
'nothing'
self
.
assertEqual
(
server_result
,
expected
,
msg
%
(
server_result
,
"server"
))
try
:
stats
=
server_params_test
(
client_context
,
server_context
,
chatty
=
True
,
connectionchatty
=
True
)
except
ssl
.
SSLError
as
e
:
stats
=
e
if
expected
is
None
and
IS_OPENSSL_1_1
:
# OpenSSL 1.1.0 raises handshake error
self
.
assertIsInstance
(
stats
,
ssl
.
SSLError
)
else
:
msg
=
"failed trying %s (s) and %s (c).
\
n
"
\
"was expecting %s, but got %%s from the %%s"
\
%
(
str
(
server_protocols
),
str
(
client_protocols
),
str
(
expected
))
client_result
=
stats
[
'client_alpn_protocol'
]
self
.
assertEqual
(
client_result
,
expected
,
msg
%
(
client_result
,
"client"
))
server_result
=
stats
[
'server_alpn_protocols'
][
-
1
]
\
if
len
(
stats
[
'server_alpn_protocols'
])
else
'nothing'
self
.
assertEqual
(
server_result
,
expected
,
msg
%
(
server_result
,
"server"
))
def
test_selected_npn_protocol
(
self
):
# selected_npn_protocol() is None unless NPN is used
...
...
Misc/NEWS
View file @
c2fc7c4f
...
...
@@ -36,6 +36,8 @@ Core and Builtins
Library
-------
-
Issue
#
26470
:
Port
ssl
and
hashlib
module
to
OpenSSL
1.1.0
.
-
Issue
#
27944
:
Fix
some
memory
-
corruption
bugs
in
the
log
reading
code
of
the
_hotshot
module
.
...
...
Modules/_hashopenssl.c
View file @
c2fc7c4f
...
...
@@ -37,8 +37,10 @@
/* EVP is the preferred interface to hashing in OpenSSL */
#include <openssl/evp.h>
#include <openssl/hmac.h>
#include <openssl/err.h>
/* We use the object interface to discover what hashes OpenSSL supports. */
#include <openssl/objects.h>
#include "openssl/err.h"
#define MUNCH_SIZE INT_MAX
...
...
@@ -50,15 +52,26 @@
#define HASH_OBJ_CONSTRUCTOR 0
#endif
/* Minimum OpenSSL version needed to support sha224 and higher. */
#if defined(OPENSSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER >= 0x00908000)
#define _OPENSSL_SUPPORTS_SHA2
#endif
#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(LIBRESSL_VERSION_NUMBER)
/* OpenSSL < 1.1.0 */
#define EVP_MD_CTX_new EVP_MD_CTX_create
#define EVP_MD_CTX_free EVP_MD_CTX_destroy
#define HAS_FAST_PKCS5_PBKDF2_HMAC 0
#include <openssl/hmac.h>
#else
/* OpenSSL >= 1.1.0 */
#define HAS_FAST_PKCS5_PBKDF2_HMAC 1
#endif
typedef
struct
{
PyObject_HEAD
PyObject
*
name
;
/* name of this hash algorithm */
EVP_MD_CTX
ctx
;
/* OpenSSL message digest context */
EVP_MD_CTX
*
ctx
;
/* OpenSSL message digest context */
#ifdef WITH_THREAD
PyThread_type_lock
lock
;
/* OpenSSL context lock */
#endif
...
...
@@ -70,7 +83,6 @@ static PyTypeObject EVPtype;
#define DEFINE_CONSTS_FOR_NEW(Name) \
static PyObject *CONST_ ## Name ## _name_obj = NULL; \
static EVP_MD_CTX CONST_new_ ## Name ## _ctx; \
static EVP_MD_CTX *CONST_new_ ## Name ## _ctx_p = NULL;
DEFINE_CONSTS_FOR_NEW
(
md5
)
...
...
@@ -83,19 +95,56 @@ DEFINE_CONSTS_FOR_NEW(sha512)
#endif
/* LCOV_EXCL_START */
static
PyObject
*
_setException
(
PyObject
*
exc
)
{
unsigned
long
errcode
;
const
char
*
lib
,
*
func
,
*
reason
;
errcode
=
ERR_peek_last_error
();
if
(
!
errcode
)
{
PyErr_SetString
(
exc
,
"unknown reasons"
);
return
NULL
;
}
ERR_clear_error
();
lib
=
ERR_lib_error_string
(
errcode
);
func
=
ERR_func_error_string
(
errcode
);
reason
=
ERR_reason_error_string
(
errcode
);
if
(
lib
&&
func
)
{
PyErr_Format
(
exc
,
"[%s: %s] %s"
,
lib
,
func
,
reason
);
}
else
if
(
lib
)
{
PyErr_Format
(
exc
,
"[%s] %s"
,
lib
,
reason
);
}
else
{
PyErr_SetString
(
exc
,
reason
);
}
return
NULL
;
}
/* LCOV_EXCL_STOP */
static
EVPobject
*
newEVPobject
(
PyObject
*
name
)
{
EVPobject
*
retval
=
(
EVPobject
*
)
PyObject_New
(
EVPobject
,
&
EVPtype
);
if
(
retval
==
NULL
)
return
NULL
;
retval
->
ctx
=
EVP_MD_CTX_new
();
if
(
retval
->
ctx
==
NULL
)
{
PyErr_NoMemory
();
return
NULL
;
}
/* save the name for .name to return */
if
(
retval
!=
NULL
)
{
Py_INCREF
(
name
);
retval
->
name
=
name
;
Py_INCREF
(
name
);
retval
->
name
=
name
;
#ifdef WITH_THREAD
retval
->
lock
=
NULL
;
retval
->
lock
=
NULL
;
#endif
}
return
retval
;
}
...
...
@@ -111,7 +160,7 @@ EVP_hash(EVPobject *self, const void *vp, Py_ssize_t len)
process
=
MUNCH_SIZE
;
else
process
=
Py_SAFE_DOWNCAST
(
len
,
Py_ssize_t
,
unsigned
int
);
EVP_DigestUpdate
(
&
self
->
ctx
,
(
const
void
*
)
cp
,
process
);
EVP_DigestUpdate
(
self
->
ctx
,
(
const
void
*
)
cp
,
process
);
len
-=
process
;
cp
+=
process
;
}
...
...
@@ -126,16 +175,20 @@ EVP_dealloc(EVPobject *self)
if
(
self
->
lock
!=
NULL
)
PyThread_free_lock
(
self
->
lock
);
#endif
EVP_MD_CTX_
cleanup
(
&
self
->
ctx
);
EVP_MD_CTX_
free
(
self
->
ctx
);
Py_XDECREF
(
self
->
name
);
PyObject_Del
(
self
);
}
static
void
locked_EVP_MD_CTX_copy
(
EVP_MD_CTX
*
new_ctx_p
,
EVPobject
*
self
)
static
int
locked_EVP_MD_CTX_copy
(
EVP_MD_CTX
*
new_ctx_p
,
EVPobject
*
self
)
{
int
result
;
ENTER_HASHLIB
(
self
);
EVP_MD_CTX_copy
(
new_ctx_p
,
&
self
->
ctx
);
/* XXX no error reporting */
result
=
EVP_MD_CTX_copy
(
new_ctx_p
,
self
->
ctx
);
LEAVE_HASHLIB
(
self
);
return
result
;
}
/* External methods for a hash object */
...
...
@@ -151,7 +204,9 @@ EVP_copy(EVPobject *self, PyObject *unused)
if
(
(
newobj
=
newEVPobject
(
self
->
name
))
==
NULL
)
return
NULL
;
locked_EVP_MD_CTX_copy
(
&
newobj
->
ctx
,
self
);
if
(
!
locked_EVP_MD_CTX_copy
(
newobj
->
ctx
,
self
))
{
return
_setException
(
PyExc_ValueError
);
}
return
(
PyObject
*
)
newobj
;
}
...
...
@@ -162,16 +217,24 @@ static PyObject *
EVP_digest
(
EVPobject
*
self
,
PyObject
*
unused
)
{
unsigned
char
digest
[
EVP_MAX_MD_SIZE
];
EVP_MD_CTX
temp_ctx
;
EVP_MD_CTX
*
temp_ctx
;
PyObject
*
retval
;
unsigned
int
digest_size
;
locked_EVP_MD_CTX_copy
(
&
temp_ctx
,
self
);
digest_size
=
EVP_MD_CTX_size
(
&
temp_ctx
);
EVP_DigestFinal
(
&
temp_ctx
,
digest
,
NULL
);
temp_ctx
=
EVP_MD_CTX_new
();
if
(
temp_ctx
==
NULL
)
{
PyErr_NoMemory
();
return
NULL
;
}
if
(
!
locked_EVP_MD_CTX_copy
(
temp_ctx
,
self
))
{
return
_setException
(
PyExc_ValueError
);
}
digest_size
=
EVP_MD_CTX_size
(
temp_ctx
);
EVP_DigestFinal
(
temp_ctx
,
digest
,
NULL
);
retval
=
PyString_FromStringAndSize
((
const
char
*
)
digest
,
digest_size
);
EVP_MD_CTX_
cleanup
(
&
temp_ctx
);
EVP_MD_CTX_
free
(
temp_ctx
);
return
retval
;
}
...
...
@@ -182,17 +245,25 @@ static PyObject *
EVP_hexdigest
(
EVPobject
*
self
,
PyObject
*
unused
)
{
unsigned
char
digest
[
EVP_MAX_MD_SIZE
];
EVP_MD_CTX
temp_ctx
;
EVP_MD_CTX
*
temp_ctx
;
PyObject
*
retval
;
char
*
hex_digest
;
unsigned
int
i
,
j
,
digest_size
;
temp_ctx
=
EVP_MD_CTX_new
();
if
(
temp_ctx
==
NULL
)
{
PyErr_NoMemory
();
return
NULL
;
}
/* Get the raw (binary) digest value */
locked_EVP_MD_CTX_copy
(
&
temp_ctx
,
self
);
digest_size
=
EVP_MD_CTX_size
(
&
temp_ctx
);
EVP_DigestFinal
(
&
temp_ctx
,
digest
,
NULL
);
if
(
!
locked_EVP_MD_CTX_copy
(
temp_ctx
,
self
))
{
return
_setException
(
PyExc_ValueError
);
}
digest_size
=
EVP_MD_CTX_size
(
temp_ctx
);
EVP_DigestFinal
(
temp_ctx
,
digest
,
NULL
);
EVP_MD_CTX_
cleanup
(
&
temp_ctx
);
EVP_MD_CTX_
free
(
temp_ctx
);
/* Create a new string */
/* NOTE: not thread safe! modifying an already created string object */
...
...
@@ -266,7 +337,7 @@ static PyObject *
EVP_get_block_size
(
EVPobject
*
self
,
void
*
closure
)
{
long
block_size
;
block_size
=
EVP_MD_CTX_block_size
(
&
self
->
ctx
);
block_size
=
EVP_MD_CTX_block_size
(
self
->
ctx
);
return
PyLong_FromLong
(
block_size
);
}
...
...
@@ -274,7 +345,7 @@ static PyObject *
EVP_get_digest_size
(
EVPobject
*
self
,
void
*
closure
)
{
long
size
;
size
=
EVP_MD_CTX_size
(
&
self
->
ctx
);
size
=
EVP_MD_CTX_size
(
self
->
ctx
);
return
PyLong_FromLong
(
size
);
}
...
...
@@ -338,7 +409,7 @@ EVP_tp_init(EVPobject *self, PyObject *args, PyObject *kwds)
PyBuffer_Release
(
&
view
);
return
-
1
;
}
EVP_DigestInit
(
&
self
->
ctx
,
digest
);
EVP_DigestInit
(
self
->
ctx
,
digest
);
self
->
name
=
name_obj
;
Py_INCREF
(
self
->
name
);
...
...
@@ -435,9 +506,9 @@ EVPnew(PyObject *name_obj,
return
NULL
;
if
(
initial_ctx
)
{
EVP_MD_CTX_copy
(
&
self
->
ctx
,
initial_ctx
);
EVP_MD_CTX_copy
(
self
->
ctx
,
initial_ctx
);
}
else
{
EVP_DigestInit
(
&
self
->
ctx
,
digest
);
EVP_DigestInit
(
self
->
ctx
,
digest
);
}
if
(
cp
&&
len
)
{
...
...
@@ -499,6 +570,7 @@ EVP_new(PyObject *self, PyObject *args, PyObject *kwdict)
#define PY_PBKDF2_HMAC 1
#if !HAS_FAST_PKCS5_PBKDF2_HMAC
/* Improved implementation of PKCS5_PBKDF2_HMAC()
*
* PKCS5_PBKDF2_HMAC_fast() hashes the password exactly one time instead of
...
...
@@ -580,37 +652,8 @@ PKCS5_PBKDF2_HMAC_fast(const char *pass, int passlen,
HMAC_CTX_cleanup
(
&
hctx_tpl
);
return
1
;
}
#endif
/* LCOV_EXCL_START */
static
PyObject
*
_setException
(
PyObject
*
exc
)
{
unsigned
long
errcode
;
const
char
*
lib
,
*
func
,
*
reason
;
errcode
=
ERR_peek_last_error
();
if
(
!
errcode
)
{
PyErr_SetString
(
exc
,
"unknown reasons"
);
return
NULL
;
}
ERR_clear_error
();
lib
=
ERR_lib_error_string
(
errcode
);
func
=
ERR_func_error_string
(
errcode
);
reason
=
ERR_reason_error_string
(
errcode
);
if
(
lib
&&
func
)
{
PyErr_Format
(
exc
,
"[%s: %s] %s"
,
lib
,
func
,
reason
);
}
else
if
(
lib
)
{
PyErr_Format
(
exc
,
"[%s] %s"
,
lib
,
reason
);
}
else
{
PyErr_SetString
(
exc
,
reason
);
}
return
NULL
;
}
/* LCOV_EXCL_STOP */
PyDoc_STRVAR
(
pbkdf2_hmac__doc__
,
"pbkdf2_hmac(hash_name, password, salt, iterations, dklen=None) -> key
\n
\
...
...
@@ -692,10 +735,17 @@ pbkdf2_hmac(PyObject *self, PyObject *args, PyObject *kwdict)
key
=
PyBytes_AS_STRING
(
key_obj
);
Py_BEGIN_ALLOW_THREADS
#if HAS_FAST_PKCS5_PBKDF2_HMAC
retval
=
PKCS5_PBKDF2_HMAC
((
char
*
)
password
.
buf
,
(
int
)
password
.
len
,
(
unsigned
char
*
)
salt
.
buf
,
(
int
)
salt
.
len
,
iterations
,
digest
,
dklen
,
(
unsigned
char
*
)
key
);
#else
retval
=
PKCS5_PBKDF2_HMAC_fast
((
char
*
)
password
.
buf
,
(
int
)
password
.
len
,
(
unsigned
char
*
)
salt
.
buf
,
(
int
)
salt
.
len
,
iterations
,
digest
,
dklen
,
(
unsigned
char
*
)
key
);
#endif
Py_END_ALLOW_THREADS
if
(
!
retval
)
{
...
...
@@ -807,7 +857,7 @@ generate_hash_name_list(void)
if (CONST_ ## NAME ## _name_obj == NULL) { \
CONST_ ## NAME ## _name_obj = PyString_FromString(#NAME); \
if (EVP_get_digestbyname(#NAME)) { \
CONST_new_ ## NAME ## _ctx_p =
&CONST_new_ ## NAME ## _ctx
; \
CONST_new_ ## NAME ## _ctx_p =
EVP_MD_CTX_new()
; \
EVP_DigestInit(CONST_new_ ## NAME ## _ctx_p, EVP_get_digestbyname(#NAME)); \
} \
} \
...
...
Modules/_ssl.c
View file @
c2fc7c4f
...
...
@@ -52,6 +52,14 @@
#include <sys/poll.h>
#endif
/* Don't warn about deprecated functions */
#ifdef __GNUC__
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
#ifdef __clang__
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
#endif
/* Include OpenSSL header files */
#include "openssl/rsa.h"
#include "openssl/crypto.h"
...
...
@@ -87,6 +95,10 @@ struct py_ssl_library_code {
/* Include generated data (error codes) */
#include "_ssl_data.h"
#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(LIBRESSL_VERSION_NUMBER)
# define OPENSSL_VERSION_1_1 1
#endif
/* Openssl comes with TLSv1.1 and TLSv1.2 between 1.0.0h and 1.0.1
http://www.openssl.org/news/changelog.html
*/
...
...
@@ -110,6 +122,70 @@ struct py_ssl_library_code {
# define HAVE_ALPN
#endif
#ifndef INVALID_SOCKET
/* MS defines this */
#define INVALID_SOCKET (-1)
#endif
#ifdef OPENSSL_VERSION_1_1
/* OpenSSL 1.1.0+ */
#ifndef OPENSSL_NO_SSL2
#define OPENSSL_NO_SSL2
#endif
#else
/* OpenSSL < 1.1.0 */
#if defined(WITH_THREAD)
#define HAVE_OPENSSL_CRYPTO_LOCK
#endif
#define TLS_method SSLv23_method
static
int
X509_NAME_ENTRY_set
(
const
X509_NAME_ENTRY
*
ne
)
{
return
ne
->
set
;
}
#ifndef OPENSSL_NO_COMP
static
int
COMP_get_type
(
const
COMP_METHOD
*
meth
)
{
return
meth
->
type
;
}
static
const
char
*
COMP_get_name
(
const
COMP_METHOD
*
meth
)
{
return
meth
->
name
;
}
#endif
static
pem_password_cb
*
SSL_CTX_get_default_passwd_cb
(
SSL_CTX
*
ctx
)
{
return
ctx
->
default_passwd_callback
;
}
static
void
*
SSL_CTX_get_default_passwd_cb_userdata
(
SSL_CTX
*
ctx
)
{
return
ctx
->
default_passwd_callback_userdata
;
}
static
int
X509_OBJECT_get_type
(
X509_OBJECT
*
x
)
{
return
x
->
type
;
}
static
X509
*
X509_OBJECT_get0_X509
(
X509_OBJECT
*
x
)
{
return
x
->
data
.
x509
;
}
static
STACK_OF
(
X509_OBJECT
)
*
X509_STORE_get0_objects
(
X509_STORE
*
store
)
{
return
store
->
objs
;
}
static
X509_VERIFY_PARAM
*
X509_STORE_get0_param
(
X509_STORE
*
store
)
{
return
store
->
param
;
}
#endif
/* OpenSSL < 1.1.0 or LibreSSL */
enum
py_ssl_error
{
/* these mirror ssl.h */
PY_SSL_ERROR_NONE
,
...
...
@@ -140,7 +216,7 @@ enum py_ssl_cert_requirements {
enum
py_ssl_version
{
PY_SSL_VERSION_SSL2
,
PY_SSL_VERSION_SSL3
=
1
,
PY_SSL_VERSION_
SSL23
,
PY_SSL_VERSION_
TLS
,
#if HAVE_TLSv1_2
PY_SSL_VERSION_TLS1
,
PY_SSL_VERSION_TLS1_1
,
...
...
@@ -681,7 +757,7 @@ _create_tuple_for_X509_NAME (X509_NAME *xname)
/* check to see if we've gotten to a new RDN */
if
(
rdn_level
>=
0
)
{
if
(
rdn_level
!=
entry
->
set
)
{
if
(
rdn_level
!=
X509_NAME_ENTRY_set
(
entry
)
)
{
/* yes, new RDN */
/* add old RDN to DN */
rdnt
=
PyList_AsTuple
(
rdn
);
...
...
@@ -698,7 +774,7 @@ _create_tuple_for_X509_NAME (X509_NAME *xname)
goto
fail0
;
}
}
rdn_level
=
entry
->
set
;
rdn_level
=
X509_NAME_ENTRY_set
(
entry
)
;
/* now add this attribute to the current RDN */
name
=
X509_NAME_ENTRY_get_object
(
entry
);
...
...
@@ -801,18 +877,18 @@ _get_peer_alt_names (X509 *certificate) {
goto
fail
;
}
p
=
ext
->
value
->
data
;
p
=
X509_EXTENSION_get_data
(
ext
)
->
data
;
if
(
method
->
it
)
names
=
(
GENERAL_NAMES
*
)
(
ASN1_item_d2i
(
NULL
,
&
p
,
ext
->
value
->
length
,
X509_EXTENSION_get_data
(
ext
)
->
length
,
ASN1_ITEM_ptr
(
method
->
it
)));
else
names
=
(
GENERAL_NAMES
*
)
(
method
->
d2i
(
NULL
,
&
p
,
ext
->
value
->
length
));
X509_EXTENSION_get_data
(
ext
)
->
length
));
for
(
j
=
0
;
j
<
sk_GENERAL_NAME_num
(
names
);
j
++
)
{
/* get a rendering of each name in the set of names */
...
...
@@ -1021,13 +1097,11 @@ _get_crl_dp(X509 *certificate) {
int
i
,
j
;
PyObject
*
lst
,
*
res
=
NULL
;
#if OPENSSL_VERSION_NUMBER < 0x10001000L
dps
=
X509_get_ext_d2i
(
certificate
,
NID_crl_distribution_points
,
NULL
,
NULL
);
#else
#if OPENSSL_VERSION_NUMBER >= 0x10001000L
/* Calls x509v3_cache_extensions and sets up crldp */
X509_check_ca
(
certificate
);
dps
=
certificate
->
crldp
;
#endif
dps
=
X509_get_ext_d2i
(
certificate
,
NID_crl_distribution_points
,
NULL
,
NULL
);
if
(
dps
==
NULL
)
return
Py_None
;
...
...
@@ -1443,9 +1517,9 @@ static PyObject *PySSL_compression(PySSLSocket *self) {
if
(
self
->
ssl
==
NULL
)
Py_RETURN_NONE
;
comp_method
=
SSL_get_current_compression
(
self
->
ssl
);
if
(
comp_method
==
NULL
||
comp_method
->
type
==
NID_undef
)
if
(
comp_method
==
NULL
||
COMP_get_type
(
comp_method
)
==
NID_undef
)
Py_RETURN_NONE
;
short_name
=
OBJ_nid2sn
(
comp_method
->
type
);
short_name
=
COMP_get_name
(
comp_method
);
if
(
short_name
==
NULL
)
Py_RETURN_NONE
;
return
PyBytes_FromString
(
short_name
);
...
...
@@ -1994,7 +2068,7 @@ context_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
char
*
kwlist
[]
=
{
"protocol"
,
NULL
};
PySSLContext
*
self
;
int
proto_version
=
PY_SSL_VERSION_
SSL23
;
int
proto_version
=
PY_SSL_VERSION_
TLS
;
long
options
;
SSL_CTX
*
ctx
=
NULL
;
...
...
@@ -2020,8 +2094,8 @@ context_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
else
if
(
proto_version
==
PY_SSL_VERSION_SSL2
)
ctx
=
SSL_CTX_new
(
SSLv2_method
());
#endif
else
if
(
proto_version
==
PY_SSL_VERSION_
SSL23
)
ctx
=
SSL_CTX_new
(
SSLv23
_method
());
else
if
(
proto_version
==
PY_SSL_VERSION_
TLS
)
ctx
=
SSL_CTX_new
(
TLS
_method
());
else
proto_version
=
-
1
;
PySSL_END_ALLOW_THREADS
...
...
@@ -2067,8 +2141,9 @@ context_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
#ifndef OPENSSL_NO_ECDH
/* Allow automatic ECDH curve selection (on OpenSSL 1.0.2+), or use
prime256v1 by default. This is Apache mod_ssl's initialization
policy, so we should be safe. */
#if defined(SSL_CTX_set_ecdh_auto)
policy, so we should be safe. OpenSSL 1.1 has it enabled by default.
*/
#if defined(SSL_CTX_set_ecdh_auto) && !defined(OPENSSL_VERSION_1_1)
SSL_CTX_set_ecdh_auto
(
self
->
ctx
,
1
);
#else
{
...
...
@@ -2336,10 +2411,12 @@ static PyObject *
get_verify_flags
(
PySSLContext
*
self
,
void
*
c
)
{
X509_STORE
*
store
;
X509_VERIFY_PARAM
*
param
;
unsigned
long
flags
;
store
=
SSL_CTX_get_cert_store
(
self
->
ctx
);
flags
=
X509_VERIFY_PARAM_get_flags
(
store
->
param
);
param
=
X509_STORE_get0_param
(
store
);
flags
=
X509_VERIFY_PARAM_get_flags
(
param
);
return
PyLong_FromUnsignedLong
(
flags
);
}
...
...
@@ -2347,22 +2424,24 @@ static int
set_verify_flags
(
PySSLContext
*
self
,
PyObject
*
arg
,
void
*
c
)
{
X509_STORE
*
store
;
X509_VERIFY_PARAM
*
param
;
unsigned
long
new_flags
,
flags
,
set
,
clear
;
if
(
!
PyArg_Parse
(
arg
,
"k"
,
&
new_flags
))
return
-
1
;
store
=
SSL_CTX_get_cert_store
(
self
->
ctx
);
flags
=
X509_VERIFY_PARAM_get_flags
(
store
->
param
);
param
=
X509_STORE_get0_param
(
store
);
flags
=
X509_VERIFY_PARAM_get_flags
(
param
);
clear
=
flags
&
~
new_flags
;
set
=
~
flags
&
new_flags
;
if
(
clear
)
{
if
(
!
X509_VERIFY_PARAM_clear_flags
(
store
->
param
,
clear
))
{
if
(
!
X509_VERIFY_PARAM_clear_flags
(
param
,
clear
))
{
_setSSLError
(
NULL
,
0
,
__FILE__
,
__LINE__
);
return
-
1
;
}
}
if
(
set
)
{
if
(
!
X509_VERIFY_PARAM_set_flags
(
store
->
param
,
set
))
{
if
(
!
X509_VERIFY_PARAM_set_flags
(
param
,
set
))
{
_setSSLError
(
NULL
,
0
,
__FILE__
,
__LINE__
);
return
-
1
;
}
...
...
@@ -2537,8 +2616,8 @@ load_cert_chain(PySSLContext *self, PyObject *args, PyObject *kwds)
char
*
kwlist
[]
=
{
"certfile"
,
"keyfile"
,
"password"
,
NULL
};
PyObject
*
keyfile
=
NULL
,
*
keyfile_bytes
=
NULL
,
*
password
=
NULL
;
char
*
certfile_bytes
=
NULL
;
pem_password_cb
*
orig_passwd_cb
=
self
->
ctx
->
default_passwd_callback
;
void
*
orig_passwd_userdata
=
self
->
ctx
->
default_passwd_callback_userdata
;
pem_password_cb
*
orig_passwd_cb
=
SSL_CTX_get_default_passwd_cb
(
self
->
ctx
)
;
void
*
orig_passwd_userdata
=
SSL_CTX_get_default_passwd_cb_userdata
(
self
->
ctx
)
;
_PySSLPasswordInfo
pw_info
=
{
NULL
,
NULL
,
NULL
,
0
,
0
};
int
r
;
...
...
@@ -2674,8 +2753,9 @@ _add_ca_certs(PySSLContext *self, void *data, Py_ssize_t len,
cert
=
d2i_X509_bio
(
biobuf
,
NULL
);
}
else
{
cert
=
PEM_read_bio_X509
(
biobuf
,
NULL
,
self
->
ctx
->
default_passwd_callback
,
self
->
ctx
->
default_passwd_callback_userdata
);
SSL_CTX_get_default_passwd_cb
(
self
->
ctx
),
SSL_CTX_get_default_passwd_cb_userdata
(
self
->
ctx
)
);
}
if
(
cert
==
NULL
)
{
break
;
...
...
@@ -3160,25 +3240,24 @@ static PyObject *
cert_store_stats
(
PySSLContext
*
self
)
{
X509_STORE
*
store
;
STACK_OF
(
X509_OBJECT
)
*
objs
;
X509_OBJECT
*
obj
;
int
x509
=
0
,
crl
=
0
,
pkey
=
0
,
ca
=
0
,
i
;
int
x509
=
0
,
crl
=
0
,
ca
=
0
,
i
;
store
=
SSL_CTX_get_cert_store
(
self
->
ctx
);
for
(
i
=
0
;
i
<
sk_X509_OBJECT_num
(
store
->
objs
);
i
++
)
{
obj
=
sk_X509_OBJECT_value
(
store
->
objs
,
i
);
switch
(
obj
->
type
)
{
objs
=
X509_STORE_get0_objects
(
store
);
for
(
i
=
0
;
i
<
sk_X509_OBJECT_num
(
objs
);
i
++
)
{
obj
=
sk_X509_OBJECT_value
(
objs
,
i
);
switch
(
X509_OBJECT_get_type
(
obj
))
{
case
X509_LU_X509
:
x509
++
;
if
(
X509_check_ca
(
obj
->
data
.
x509
))
{
if
(
X509_check_ca
(
X509_OBJECT_get0_X509
(
obj
)
))
{
ca
++
;
}
break
;
case
X509_LU_CRL
:
crl
++
;
break
;
case
X509_LU_PKEY
:
pkey
++
;
break
;
default:
/* Ignore X509_LU_FAIL, X509_LU_RETRY, X509_LU_PKEY.
* As far as I can tell they are internal states and never
...
...
@@ -3204,6 +3283,7 @@ get_ca_certs(PySSLContext *self, PyObject *args, PyObject *kwds)
char
*
kwlist
[]
=
{
"binary_form"
,
NULL
};
X509_STORE
*
store
;
PyObject
*
ci
=
NULL
,
*
rlist
=
NULL
,
*
py_binary_mode
=
Py_False
;
STACK_OF
(
X509_OBJECT
)
*
objs
;
int
i
;
int
binary_mode
=
0
;
...
...
@@ -3221,17 +3301,18 @@ get_ca_certs(PySSLContext *self, PyObject *args, PyObject *kwds)
}
store
=
SSL_CTX_get_cert_store
(
self
->
ctx
);
for
(
i
=
0
;
i
<
sk_X509_OBJECT_num
(
store
->
objs
);
i
++
)
{
objs
=
X509_STORE_get0_objects
(
store
);
for
(
i
=
0
;
i
<
sk_X509_OBJECT_num
(
objs
);
i
++
)
{
X509_OBJECT
*
obj
;
X509
*
cert
;
obj
=
sk_X509_OBJECT_value
(
store
->
objs
,
i
);
if
(
obj
->
type
!=
X509_LU_X509
)
{
obj
=
sk_X509_OBJECT_value
(
objs
,
i
);
if
(
X509_OBJECT_get_type
(
obj
)
!=
X509_LU_X509
)
{
/* not a x509 cert */
continue
;
}
/* CA for any purpose */
cert
=
obj
->
data
.
x509
;
cert
=
X509_OBJECT_get0_X509
(
obj
)
;
if
(
!
X509_check_ca
(
cert
))
{
continue
;
}
...
...
@@ -3842,10 +3923,12 @@ static PyMethodDef PySSL_methods[] = {
};
#ifdef
WITH_THREAD
#ifdef
HAVE_OPENSSL_CRYPTO_LOCK
/* an implementation of OpenSSL threading operations in terms
of the Python C thread library */
* of the Python C thread library
* Only used up to 1.0.2. OpenSSL 1.1.0+ has its own locking code.
*/
static
PyThread_type_lock
*
_ssl_locks
=
NULL
;
...
...
@@ -3926,7 +4009,7 @@ static int _setup_ssl_threads(void) {
return
1
;
}
#endif
/*
def HAVE_THREAD
*/
#endif
/*
HAVE_OPENSSL_CRYPTO_LOCK for WITH_THREAD && OpenSSL < 1.1.0
*/
PyDoc_STRVAR
(
module_doc
,
"Implementation module for SSL socket operations. See the socket module
\n
\
...
...
@@ -3979,11 +4062,16 @@ init_ssl(void)
SSL_load_error_strings
();
SSL_library_init
();
#ifdef WITH_THREAD
#ifdef HAVE_OPENSSL_CRYPTO_LOCK
/* note that this will start threading if not already started */
if
(
!
_setup_ssl_threads
())
{
return
;
}
#elif OPENSSL_VERSION_1_1 && defined(OPENSSL_THREADS)
/* OpenSSL 1.1.0 builtin thread support is enabled */
_ssl_locks_count
++
;
#endif
#endif
/* WITH_THREAD */
OpenSSL_add_all_algorithms
();
/* Add symbols to module dict */
...
...
@@ -4136,7 +4224,9 @@ init_ssl(void)
PY_SSL_VERSION_SSL3
);
#endif
PyModule_AddIntConstant
(
m
,
"PROTOCOL_SSLv23"
,
PY_SSL_VERSION_SSL23
);
PY_SSL_VERSION_TLS
);
PyModule_AddIntConstant
(
m
,
"PROTOCOL_TLS"
,
PY_SSL_VERSION_TLS
);
PyModule_AddIntConstant
(
m
,
"PROTOCOL_TLSv1"
,
PY_SSL_VERSION_TLS1
);
#if HAVE_TLSv1_2
...
...
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