blob: b987ec339de7138cb45da115519c23026d802a19 [file] [log] [blame]
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +00001# Wrapper module for _ssl, providing some additional facilities
2# implemented in Python. Written by Bill Janssen.
3
4"""\
5This module provides some more Pythonic support for SSL.
6
7Object types:
8
Bill Janssen98d19da2007-09-10 21:51:02 +00009 SSLSocket -- subtype of socket.socket which does SSL over the socket
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +000010
11Exceptions:
12
Bill Janssen98d19da2007-09-10 21:51:02 +000013 SSLError -- exception raised for I/O errors
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +000014
15Functions:
16
17 cert_time_to_seconds -- convert time string used for certificate
18 notBefore and notAfter functions to integer
19 seconds past the Epoch (the time values
20 returned from time.time())
21
22 fetch_server_certificate (HOST, PORT) -- fetch the certificate provided
23 by the server running on HOST at port PORT. No
24 validation of the certificate is performed.
25
26Integer constants:
27
28SSL_ERROR_ZERO_RETURN
29SSL_ERROR_WANT_READ
30SSL_ERROR_WANT_WRITE
31SSL_ERROR_WANT_X509_LOOKUP
32SSL_ERROR_SYSCALL
33SSL_ERROR_SSL
34SSL_ERROR_WANT_CONNECT
35
36SSL_ERROR_EOF
37SSL_ERROR_INVALID_ERROR_CODE
38
39The following group define certificate requirements that one side is
40allowing/requiring from the other side:
41
42CERT_NONE - no certificates from the other side are required (or will
43 be looked at if provided)
44CERT_OPTIONAL - certificates are not required, but if provided will be
45 validated, and if validation fails, the connection will
46 also fail
47CERT_REQUIRED - certificates are required, and will be validated, and
48 if validation fails, the connection will also fail
49
50The following constants identify various SSL protocol variants:
51
52PROTOCOL_SSLv2
53PROTOCOL_SSLv3
54PROTOCOL_SSLv23
55PROTOCOL_TLSv1
56"""
57
58import os, sys
59
60import _ssl # if we can't import it, let the error propagate
Bill Janssen98d19da2007-09-10 21:51:02 +000061
62from _ssl import SSLError
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +000063from _ssl import CERT_NONE, CERT_OPTIONAL, CERT_REQUIRED
64from _ssl import PROTOCOL_SSLv2, PROTOCOL_SSLv3, PROTOCOL_SSLv23, PROTOCOL_TLSv1
Bill Janssen98d19da2007-09-10 21:51:02 +000065from _ssl import RAND_status, RAND_egd, RAND_add
Bill Janssen426ea0a2007-08-29 22:35:05 +000066from _ssl import \
67 SSL_ERROR_ZERO_RETURN, \
68 SSL_ERROR_WANT_READ, \
69 SSL_ERROR_WANT_WRITE, \
70 SSL_ERROR_WANT_X509_LOOKUP, \
71 SSL_ERROR_SYSCALL, \
72 SSL_ERROR_SSL, \
73 SSL_ERROR_WANT_CONNECT, \
74 SSL_ERROR_EOF, \
75 SSL_ERROR_INVALID_ERROR_CODE
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +000076
Bill Janssen426ea0a2007-08-29 22:35:05 +000077from socket import socket
78from socket import getnameinfo as _getnameinfo
79
Bill Janssen98d19da2007-09-10 21:51:02 +000080def 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>"
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +000091
Bill Janssen98d19da2007-09-10 21:51:02 +000092
93class SSLSocket (socket):
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +000094
Bill Janssen426ea0a2007-08-29 22:35:05 +000095 """This class implements a subtype of socket.socket that wraps
96 the underlying OS socket in an SSL context when necessary, and
97 provides read and write methods over that channel."""
98
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +000099 def __init__(self, sock, keyfile=None, certfile=None,
100 server_side=False, cert_reqs=CERT_NONE,
101 ssl_version=PROTOCOL_SSLv23, ca_certs=None):
102 socket.__init__(self, _sock=sock._sock)
103 if certfile and not keyfile:
104 keyfile = certfile
Bill Janssen426ea0a2007-08-29 22:35:05 +0000105 # see if it's connected
106 try:
107 socket.getpeername(self)
108 except:
109 # no, no connection yet
110 self._sslobj = None
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000111 else:
Bill Janssen426ea0a2007-08-29 22:35:05 +0000112 # yes, create the SSL object
113 self._sslobj = _ssl.sslwrap(self._sock, server_side,
114 keyfile, certfile,
115 cert_reqs, ssl_version, ca_certs)
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000116 self.keyfile = keyfile
117 self.certfile = certfile
118 self.cert_reqs = cert_reqs
119 self.ssl_version = ssl_version
120 self.ca_certs = ca_certs
121
122 def read(self, len=1024):
Bill Janssen24bccf22007-08-30 17:07:28 +0000123
124 """Read up to LEN bytes and return them.
125 Return zero-length string on EOF."""
126
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000127 return self._sslobj.read(len)
128
129 def write(self, data):
Bill Janssen24bccf22007-08-30 17:07:28 +0000130
131 """Write DATA to the underlying SSL channel. Returns
132 number of bytes of DATA actually transmitted."""
133
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000134 return self._sslobj.write(data)
135
Bill Janssen98d19da2007-09-10 21:51:02 +0000136 def getpeercert(self, binary_form=False):
Bill Janssen24bccf22007-08-30 17:07:28 +0000137
138 """Returns a formatted version of the data in the
139 certificate provided by the other end of the SSL channel.
140 Return None if no certificate was provided, {} if a
141 certificate was provided, but not validated."""
142
Bill Janssen98d19da2007-09-10 21:51:02 +0000143 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()
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000151
152 def send (self, data, flags=0):
Bill Janssen426ea0a2007-08-29 22:35:05 +0000153 if self._sslobj:
154 if flags != 0:
155 raise ValueError(
156 "non-zero flags not allowed in calls to send() on %s" %
157 self.__class__)
158 return self._sslobj.write(data)
159 else:
160 return socket.send(self, data, flags)
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000161
162 def send_to (self, data, addr, flags=0):
Bill Janssen426ea0a2007-08-29 22:35:05 +0000163 if self._sslobj:
164 raise ValueError("send_to not allowed on instances of %s" %
165 self.__class__)
166 else:
167 return socket.send_to(self, data, addr, flags)
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000168
169 def sendall (self, data, flags=0):
Bill Janssen426ea0a2007-08-29 22:35:05 +0000170 if self._sslobj:
171 if flags != 0:
172 raise ValueError(
173 "non-zero flags not allowed in calls to sendall() on %s" %
174 self.__class__)
175 return self._sslobj.write(data)
176 else:
177 return socket.sendall(self, data, flags)
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000178
179 def recv (self, buflen=1024, flags=0):
Bill Janssen426ea0a2007-08-29 22:35:05 +0000180 if self._sslobj:
181 if flags != 0:
182 raise ValueError(
183 "non-zero flags not allowed in calls to sendall() on %s" %
184 self.__class__)
185 return self._sslobj.read(data, buflen)
186 else:
187 return socket.recv(self, buflen, flags)
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000188
189 def recv_from (self, addr, buflen=1024, flags=0):
Bill Janssen426ea0a2007-08-29 22:35:05 +0000190 if self._sslobj:
191 raise ValueError("recv_from not allowed on instances of %s" %
192 self.__class__)
193 else:
194 return socket.recv_from(self, addr, buflen, flags)
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000195
Bill Janssen426ea0a2007-08-29 22:35:05 +0000196 def ssl_shutdown(self):
Bill Janssen24bccf22007-08-30 17:07:28 +0000197
198 """Shuts down the SSL channel over this socket (if active),
199 without closing the socket connection."""
200
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000201 if self._sslobj:
202 self._sslobj.shutdown()
203 self._sslobj = None
Bill Janssen426ea0a2007-08-29 22:35:05 +0000204
205 def shutdown(self, how):
206 self.ssl_shutdown()
207 socket.shutdown(self, how)
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000208
209 def close(self):
Bill Janssen426ea0a2007-08-29 22:35:05 +0000210 self.ssl_shutdown()
211 socket.close(self)
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000212
213 def connect(self, addr):
Bill Janssen24bccf22007-08-30 17:07:28 +0000214
215 """Connects to remote ADDR, and then wraps the connection in
216 an SSL channel."""
217
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000218 # Here we assume that the socket is client-side, and not
219 # connected at the time of the call. We connect it, then wrap it.
Bill Janssen426ea0a2007-08-29 22:35:05 +0000220 if self._sslobj:
Bill Janssen98d19da2007-09-10 21:51:02 +0000221 raise ValueError("attempt to connect already-connected SSLSocket!")
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000222 socket.connect(self, addr)
Bill Janssen426ea0a2007-08-29 22:35:05 +0000223 self._sslobj = _ssl.sslwrap(self._sock, False, self.keyfile, self.certfile,
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000224 self.cert_reqs, self.ssl_version,
225 self.ca_certs)
226
227 def accept(self):
Bill Janssen24bccf22007-08-30 17:07:28 +0000228
229 """Accepts a new connection from a remote client, and returns
230 a tuple containing that new connection wrapped with a server-side
231 SSL channel, and the address of the remote client."""
232
Bill Janssen426ea0a2007-08-29 22:35:05 +0000233 newsock, addr = socket.accept(self)
Bill Janssen98d19da2007-09-10 21:51:02 +0000234 return (SSLSocket(newsock, True, self.keyfile, self.certfile,
235 self.cert_reqs, self.ssl_version,
236 self.ca_certs), addr)
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000237
238
Bill Janssen98d19da2007-09-10 21:51:02 +0000239def wrap_socket(sock, keyfile=None, certfile=None,
240 server_side=False, cert_reqs=CERT_NONE,
241 ssl_version=PROTOCOL_SSLv23, ca_certs=None):
242
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)
246
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000247# some utility functions
248
249def cert_time_to_seconds(cert_time):
Bill Janssen24bccf22007-08-30 17:07:28 +0000250
251 """Takes a date-time string in standard ASN1_print form
252 ("MON DAY 24HOUR:MINUTE:SEC YEAR TIMEZONE") and return
253 a Python time value in seconds past the epoch."""
254
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000255 import time
256 return time.mktime(time.strptime(cert_time, "%b %d %H:%M:%S %Y GMT"))
257
258# a replacement for the old socket.ssl function
259
260def sslwrap_simple (sock, keyfile=None, certfile=None):
261
Bill Janssen24bccf22007-08-30 17:07:28 +0000262 """A replacement for the old socket.ssl function. Designed
263 for compability with Python 2.5 and earlier. Will disappear in
264 Python 3.0."""
265
Guido van Rossum4f2c3dd2007-08-25 15:08:43 +0000266 return _ssl.sslwrap(sock._sock, 0, keyfile, certfile, CERT_NONE,
267 PROTOCOL_SSLv23, None)