Skip to content

Commit 98d19da

Browse files
author
Bill Janssen
committed
More work on SSL support.
* Much expanded test suite: All protocols tested against all other protocols. All protocols tested with all certificate options. Tests for bad key and bad cert. Test of STARTTLS functionality. Test of RAND_* functions. * Fixes for threading/malloc bug. * Issue 1065 fixed: sslsocket class renamed to SSLSocket. sslerror class renamed to SSLError. Function "wrap_socket" now used to wrap an existing socket. * Issue 1583946 finally fixed: Support for subjectAltName added. Subject name now returned as proper DN list of RDNs. * SSLError exported from socket as "sslerror". * RAND_* functions properly exported from ssl.py. * Documentation improved: Example of how to create a self-signed certificate. Better indexing.
1 parent a0c0551 commit 98d19da

15 files changed

Lines changed: 1593 additions & 510 deletions

File tree

β€ŽDoc/library/hashlib.rstβ€Ž

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ using the :meth:`update` method. At any point you can ask it for the
3232
:dfn:`digest` of the concatenation of the strings fed to it so far using the
3333
:meth:`digest` or :meth:`hexdigest` methods.
3434

35-
.. index:: single: OpenSSL
35+
.. index:: single: OpenSSL; (use in module hashlib)
3636

3737
Constructors for hash algorithms that are always present in this module are
3838
:func:`md5`, :func:`sha1`, :func:`sha224`, :func:`sha256`, :func:`sha384`, and

β€ŽDoc/library/ssl.rstβ€Ž

Lines changed: 252 additions & 144 deletions
Large diffs are not rendered by default.

β€ŽLib/httplib.pyβ€Ž

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1051,7 +1051,7 @@ def connect(self):
10511051
"Connect to a host on a given (SSL) port."
10521052

10531053
sock = socket.create_connection((self.host, self.port), self.timeout)
1054-
self.sock = ssl.sslsocket(sock, self.key_file, self.cert_file)
1054+
self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file)
10551055

10561056
__all__.append("HTTPSConnection")
10571057

@@ -1083,7 +1083,7 @@ def __init__(self, host='', port=None, key_file=None, cert_file=None,
10831083

10841084
def FakeSocket (sock, sslobj):
10851085
warnings.warn("FakeSocket is deprecated, and won't be in 3.x. " +
1086-
"Use the result of ssl.sslsocket directly instead.",
1086+
"Use the result of ssl.wrap_socket() directly instead.",
10871087
DeprecationWarning, stacklevel=2)
10881088
return sslobj
10891089

β€ŽLib/imaplib.pyβ€Ž

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1147,7 +1147,7 @@ def open(self, host = '', port = IMAP4_SSL_PORT):
11471147
self.port = port
11481148
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
11491149
self.sock.connect((host, port))
1150-
self.sslobj = ssl.sslsocket(self.sock, self.keyfile, self.certfile)
1150+
self.sslobj = ssl.wrap_socket(self.sock, self.keyfile, self.certfile)
11511151

11521152

11531153
def read(self, size):
@@ -1199,7 +1199,7 @@ def socket(self):
11991199
def ssl(self):
12001200
"""Return SSLObject instance used to communicate with the IMAP4 server.
12011201
1202-
ssl = ssl.sslsocket(<instance>.socket)
1202+
ssl = ssl.wrap_socket(<instance>.socket)
12031203
"""
12041204
return self.sslobj
12051205

β€ŽLib/poplib.pyβ€Ž

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,7 @@ def __init__(self, host, port = POP3_SSL_PORT, keyfile = None, certfile = None):
348348
if not self.sock:
349349
raise socket.error, msg
350350
self.file = self.sock.makefile('rb')
351-
self.sslobj = ssl.sslsocket(self.sock, self.keyfile, self.certfile)
351+
self.sslobj = ssl.wrap_socket(self.sock, self.keyfile, self.certfile)
352352
self._debugging = 0
353353
self.welcome = self._getresp()
354354

β€ŽLib/smtplib.pyβ€Ž

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -587,7 +587,7 @@ def starttls(self, keyfile = None, certfile = None):
587587
if resp == 220:
588588
if not _have_ssl:
589589
raise RuntimeError("No SSL support included in this Python")
590-
self.sock = ssl.sslsocket(self.sock, keyfile, certfile)
590+
self.sock = ssl.wrap_socket(self.sock, keyfile, certfile)
591591
self.file = SSLFakeFile(self.sock)
592592
return (resp, reply)
593593

@@ -720,7 +720,7 @@ def __init__(self, host='', port=0, local_hostname=None,
720720
def _get_socket(self, host, port, timeout):
721721
if self.debuglevel > 0: print>>stderr, 'connect:', (host, port)
722722
self.sock = socket.create_connection((host, port), timeout)
723-
self.sock = ssl.sslsocket(self.sock, self.keyfile, self.certfile)
723+
self.sock = ssl.wrap_socket(self.sock, self.keyfile, self.certfile)
724724
self.file = SSLFakeFile(self.sock)
725725

726726
__all__.append("SMTP_SSL")

β€ŽLib/socket.pyβ€Ž

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,13 +56,13 @@ def ssl(sock, keyfile=None, certfile=None):
5656
# we do an internal import here because the ssl
5757
# module imports the socket module
5858
import ssl as _realssl
59-
warnings.warn("socket.ssl() is deprecated. Use ssl.sslsocket() instead.",
59+
warnings.warn("socket.ssl() is deprecated. Use ssl.wrap_socket() instead.",
6060
DeprecationWarning, stacklevel=2)
6161
return _realssl.sslwrap_simple(sock, keyfile, certfile)
6262

6363
# we need to import the same constants we used to...
64+
from _ssl import SSLError as sslerror
6465
from _ssl import \
65-
sslerror, \
6666
RAND_add, \
6767
RAND_egd, \
6868
RAND_status, \

β€ŽLib/ssl.pyβ€Ž

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@
66
77
Object types:
88
9-
sslsocket -- subtype of socket.socket which does SSL over the socket
9+
SSLSocket -- subtype of socket.socket which does SSL over the socket
1010
1111
Exceptions:
1212
13-
sslerror -- exception raised for I/O errors
13+
SSLError -- exception raised for I/O errors
1414
1515
Functions:
1616
@@ -58,9 +58,11 @@
5858
import os, sys
5959

6060
import _ssl # if we can't import it, let the error propagate
61-
from _ssl import sslerror
61+
62+
from _ssl import SSLError
6263
from _ssl import CERT_NONE, CERT_OPTIONAL, CERT_REQUIRED
6364
from _ssl import PROTOCOL_SSLv2, PROTOCOL_SSLv3, PROTOCOL_SSLv23, PROTOCOL_TLSv1
65+
from _ssl import RAND_status, RAND_egd, RAND_add
6466
from _ssl import \
6567
SSL_ERROR_ZERO_RETURN, \
6668
SSL_ERROR_WANT_READ, \
@@ -75,8 +77,20 @@
7577
from socket import socket
7678
from socket import getnameinfo as _getnameinfo
7779

80+
def get_protocol_name (protocol_code):
81+
if protocol_code == PROTOCOL_TLSv1:
82+
return "TLSv1"
83+
elif protocol_code == PROTOCOL_SSLv23:
84+
return "SSLv23"
85+
elif protocol_code == PROTOCOL_SSLv2:
86+
return "SSLv2"
87+
elif protocol_code == PROTOCOL_SSLv3:
88+
return "SSLv3"
89+
else:
90+
return "<unknown>"
91+
7892

79-
class sslsocket (socket):
93+
class SSLSocket (socket):
8094

8195
"""This class implements a subtype of socket.socket that wraps
8296
the underlying OS socket in an SSL context when necessary, and
@@ -119,14 +133,21 @@ def write(self, data):
119133

120134
return self._sslobj.write(data)
121135

122-
def getpeercert(self):
136+
def getpeercert(self, binary_form=False):
123137

124138
"""Returns a formatted version of the data in the
125139
certificate provided by the other end of the SSL channel.
126140
Return None if no certificate was provided, {} if a
127141
certificate was provided, but not validated."""
128142

129-
return self._sslobj.peer_certificate()
143+
return self._sslobj.peer_certificate(binary_form)
144+
145+
def cipher (self):
146+
147+
if not self._sslobj:
148+
return None
149+
else:
150+
return self._sslobj.cipher()
130151

131152
def send (self, data, flags=0):
132153
if self._sslobj:
@@ -197,7 +218,7 @@ def connect(self, addr):
197218
# Here we assume that the socket is client-side, and not
198219
# connected at the time of the call. We connect it, then wrap it.
199220
if self._sslobj:
200-
raise ValueError("attempt to connect already-connected sslsocket!")
221+
raise ValueError("attempt to connect already-connected SSLSocket!")
201222
socket.connect(self, addr)
202223
self._sslobj = _ssl.sslwrap(self._sock, False, self.keyfile, self.certfile,
203224
self.cert_reqs, self.ssl_version,
@@ -210,10 +231,18 @@ def accept(self):
210231
SSL channel, and the address of the remote client."""
211232

212233
newsock, addr = socket.accept(self)
213-
return (sslsocket(newsock, True, self.keyfile, self.certfile,
214-
self.cert_reqs, self.ssl_version,
215-
self.ca_certs), addr)
234+
return (SSLSocket(newsock, True, self.keyfile, self.certfile,
235+
self.cert_reqs, self.ssl_version,
236+
self.ca_certs), addr)
237+
238+
239+
def wrap_socket(sock, keyfile=None, certfile=None,
240+
server_side=False, cert_reqs=CERT_NONE,
241+
ssl_version=PROTOCOL_SSLv23, ca_certs=None):
216242

243+
return SSLSocket(sock, keyfile=keyfile, certfile=certfile,
244+
server_side=server_side, cert_reqs=cert_reqs,
245+
ssl_version=ssl_version, ca_certs=ca_certs)
217246

218247
# some utility functions
219248

β€ŽLib/test/badcert.pemβ€Ž

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
-----BEGIN RSA PRIVATE KEY-----
2+
MIICXwIBAAKBgQC8ddrhm+LutBvjYcQlnH21PPIseJ1JVG2HMmN2CmZk2YukO+9L
3+
opdJhTvbGfEj0DQs1IE8M+kTUyOmuKfVrFMKwtVeCJphrAnhoz7TYOuLBSqt7lVH
4+
fhi/VwovESJlaBOp+WMnfhcduPEYHYx/6cnVapIkZnLt30zu2um+DzA9jQIDAQAB
5+
AoGBAK0FZpaKj6WnJZN0RqhhK+ggtBWwBnc0U/ozgKz2j1s3fsShYeiGtW6CK5nU
6+
D1dZ5wzhbGThI7LiOXDvRucc9n7vUgi0alqPQ/PFodPxAN/eEYkmXQ7W2k7zwsDA
7+
IUK0KUhktQbLu8qF/m8qM86ba9y9/9YkXuQbZ3COl5ahTZrhAkEA301P08RKv3KM
8+
oXnGU2UHTuJ1MAD2hOrPxjD4/wxA/39EWG9bZczbJyggB4RHu0I3NOSFjAm3HQm0
9+
ANOu5QK9owJBANgOeLfNNcF4pp+UikRFqxk5hULqRAWzVxVrWe85FlPm0VVmHbb/
10+
loif7mqjU8o1jTd/LM7RD9f2usZyE2psaw8CQQCNLhkpX3KO5kKJmS9N7JMZSc4j
11+
oog58yeYO8BBqKKzpug0LXuQultYv2K4veaIO04iL9VLe5z9S/Q1jaCHBBuXAkEA
12+
z8gjGoi1AOp6PBBLZNsncCvcV/0aC+1se4HxTNo2+duKSDnbq+ljqOM+E7odU+Nq
13+
ewvIWOG//e8fssd0mq3HywJBAJ8l/c8GVmrpFTx8r/nZ2Pyyjt3dH1widooDXYSV
14+
q6Gbf41Llo5sYAtmxdndTLASuHKecacTgZVhy0FryZpLKrU=
15+
-----END RSA PRIVATE KEY-----
16+
-----BEGIN CERTIFICATE-----
17+
Just bad cert data
18+
-----END CERTIFICATE-----
19+
-----BEGIN RSA PRIVATE KEY-----
20+
MIICXwIBAAKBgQC8ddrhm+LutBvjYcQlnH21PPIseJ1JVG2HMmN2CmZk2YukO+9L
21+
opdJhTvbGfEj0DQs1IE8M+kTUyOmuKfVrFMKwtVeCJphrAnhoz7TYOuLBSqt7lVH
22+
fhi/VwovESJlaBOp+WMnfhcduPEYHYx/6cnVapIkZnLt30zu2um+DzA9jQIDAQAB
23+
AoGBAK0FZpaKj6WnJZN0RqhhK+ggtBWwBnc0U/ozgKz2j1s3fsShYeiGtW6CK5nU
24+
D1dZ5wzhbGThI7LiOXDvRucc9n7vUgi0alqPQ/PFodPxAN/eEYkmXQ7W2k7zwsDA
25+
IUK0KUhktQbLu8qF/m8qM86ba9y9/9YkXuQbZ3COl5ahTZrhAkEA301P08RKv3KM
26+
oXnGU2UHTuJ1MAD2hOrPxjD4/wxA/39EWG9bZczbJyggB4RHu0I3NOSFjAm3HQm0
27+
ANOu5QK9owJBANgOeLfNNcF4pp+UikRFqxk5hULqRAWzVxVrWe85FlPm0VVmHbb/
28+
loif7mqjU8o1jTd/LM7RD9f2usZyE2psaw8CQQCNLhkpX3KO5kKJmS9N7JMZSc4j
29+
oog58yeYO8BBqKKzpug0LXuQultYv2K4veaIO04iL9VLe5z9S/Q1jaCHBBuXAkEA
30+
z8gjGoi1AOp6PBBLZNsncCvcV/0aC+1se4HxTNo2+duKSDnbq+ljqOM+E7odU+Nq
31+
ewvIWOG//e8fssd0mq3HywJBAJ8l/c8GVmrpFTx8r/nZ2Pyyjt3dH1widooDXYSV
32+
q6Gbf41Llo5sYAtmxdndTLASuHKecacTgZVhy0FryZpLKrU=
33+
-----END RSA PRIVATE KEY-----
34+
-----BEGIN CERTIFICATE-----
35+
Just bad cert data
36+
-----END CERTIFICATE-----

β€ŽLib/test/badkey.pemβ€Ž

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
-----BEGIN RSA PRIVATE KEY-----
2+
Bad Key, though the cert should be OK
3+
-----END RSA PRIVATE KEY-----
4+
-----BEGIN CERTIFICATE-----
5+
MIICpzCCAhCgAwIBAgIJAP+qStv1cIGNMA0GCSqGSIb3DQEBBQUAMIGJMQswCQYD
6+
VQQGEwJVUzERMA8GA1UECBMIRGVsYXdhcmUxEzARBgNVBAcTCldpbG1pbmd0b24x
7+
IzAhBgNVBAoTGlB5dGhvbiBTb2Z0d2FyZSBGb3VuZGF0aW9uMQwwCgYDVQQLEwNT
8+
U0wxHzAdBgNVBAMTFnNvbWVtYWNoaW5lLnB5dGhvbi5vcmcwHhcNMDcwODI3MTY1
9+
NDUwWhcNMTMwMjE2MTY1NDUwWjCBiTELMAkGA1UEBhMCVVMxETAPBgNVBAgTCERl
10+
bGF3YXJlMRMwEQYDVQQHEwpXaWxtaW5ndG9uMSMwIQYDVQQKExpQeXRob24gU29m
11+
dHdhcmUgRm91bmRhdGlvbjEMMAoGA1UECxMDU1NMMR8wHQYDVQQDExZzb21lbWFj
12+
aGluZS5weXRob24ub3JnMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8ddrh
13+
m+LutBvjYcQlnH21PPIseJ1JVG2HMmN2CmZk2YukO+9LopdJhTvbGfEj0DQs1IE8
14+
M+kTUyOmuKfVrFMKwtVeCJphrAnhoz7TYOuLBSqt7lVHfhi/VwovESJlaBOp+WMn
15+
fhcduPEYHYx/6cnVapIkZnLt30zu2um+DzA9jQIDAQABoxUwEzARBglghkgBhvhC
16+
AQEEBAMCBkAwDQYJKoZIhvcNAQEFBQADgYEAF4Q5BVqmCOLv1n8je/Jw9K669VXb
17+
08hyGzQhkemEBYQd6fzQ9A/1ZzHkJKb1P6yreOLSEh4KcxYPyrLRC1ll8nr5OlCx
18+
CMhKkTnR6qBsdNV0XtdU2+N25hqW+Ma4ZeqsN/iiJVCGNOZGnvQuvCAGWF8+J/f/
19+
iHkC6gGdBJhogs4=
20+
-----END CERTIFICATE-----
21+
-----BEGIN RSA PRIVATE KEY-----
22+
Bad Key, though the cert should be OK
23+
-----END RSA PRIVATE KEY-----
24+
-----BEGIN CERTIFICATE-----
25+
MIICpzCCAhCgAwIBAgIJAP+qStv1cIGNMA0GCSqGSIb3DQEBBQUAMIGJMQswCQYD
26+
VQQGEwJVUzERMA8GA1UECBMIRGVsYXdhcmUxEzARBgNVBAcTCldpbG1pbmd0b24x
27+
IzAhBgNVBAoTGlB5dGhvbiBTb2Z0d2FyZSBGb3VuZGF0aW9uMQwwCgYDVQQLEwNT
28+
U0wxHzAdBgNVBAMTFnNvbWVtYWNoaW5lLnB5dGhvbi5vcmcwHhcNMDcwODI3MTY1
29+
NDUwWhcNMTMwMjE2MTY1NDUwWjCBiTELMAkGA1UEBhMCVVMxETAPBgNVBAgTCERl
30+
bGF3YXJlMRMwEQYDVQQHEwpXaWxtaW5ndG9uMSMwIQYDVQQKExpQeXRob24gU29m
31+
dHdhcmUgRm91bmRhdGlvbjEMMAoGA1UECxMDU1NMMR8wHQYDVQQDExZzb21lbWFj
32+
aGluZS5weXRob24ub3JnMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8ddrh
33+
m+LutBvjYcQlnH21PPIseJ1JVG2HMmN2CmZk2YukO+9LopdJhTvbGfEj0DQs1IE8
34+
M+kTUyOmuKfVrFMKwtVeCJphrAnhoz7TYOuLBSqt7lVHfhi/VwovESJlaBOp+WMn
35+
fhcduPEYHYx/6cnVapIkZnLt30zu2um+DzA9jQIDAQABoxUwEzARBglghkgBhvhC
36+
AQEEBAMCBkAwDQYJKoZIhvcNAQEFBQADgYEAF4Q5BVqmCOLv1n8je/Jw9K669VXb
37+
08hyGzQhkemEBYQd6fzQ9A/1ZzHkJKb1P6yreOLSEh4KcxYPyrLRC1ll8nr5OlCx
38+
CMhKkTnR6qBsdNV0XtdU2+N25hqW+Ma4ZeqsN/iiJVCGNOZGnvQuvCAGWF8+J/f/
39+
iHkC6gGdBJhogs4=
40+
-----END CERTIFICATE-----

0 commit comments

Comments
 (0)