Revision b14f759e
b/lib/http.py | ||
---|---|---|
209 | 209 |
return serializer.LoadJson(data) |
210 | 210 |
|
211 | 211 |
|
212 |
class _HttpSocketBase(object): |
|
213 |
"""Base class for HTTP server and client. |
|
214 |
|
|
215 |
""" |
|
216 |
def __init__(self): |
|
217 |
self._using_ssl = None |
|
218 |
self._ssl_cert = None |
|
219 |
self._ssl_key = None |
|
220 |
|
|
221 |
def _CreateSocket(self, ssl_key_path, ssl_cert_path, ssl_verify_peer): |
|
222 |
"""Creates a TCP socket and initializes SSL if needed. |
|
223 |
|
|
224 |
@type ssl_key_path: string |
|
225 |
@param ssl_key_path: Path to file containing SSL key in PEM format |
|
226 |
@type ssl_cert_path: string |
|
227 |
@param ssl_cert_path: Path to file containing SSL certificate in PEM format |
|
228 |
@type ssl_verify_peer: bool |
|
229 |
@param ssl_verify_peer: Whether to require client certificate and compare |
|
230 |
it with our certificate |
|
231 |
|
|
232 |
""" |
|
233 |
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) |
|
234 |
|
|
235 |
# Should we enable SSL? |
|
236 |
self._using_ssl = (ssl_cert_path and ssl_key_path) |
|
237 |
|
|
238 |
if not self._using_ssl: |
|
239 |
return sock |
|
240 |
|
|
241 |
ctx = OpenSSL.SSL.Context(OpenSSL.SSL.SSLv23_METHOD) |
|
242 |
ctx.set_options(OpenSSL.SSL.OP_NO_SSLv2) |
|
243 |
|
|
244 |
ssl_key_pem = utils.ReadFile(ssl_key_path) |
|
245 |
ssl_cert_pem = utils.ReadFile(ssl_cert_path) |
|
246 |
|
|
247 |
cr = OpenSSL.crypto |
|
248 |
self._ssl_cert = cr.load_certificate(cr.FILETYPE_PEM, ssl_cert_pem) |
|
249 |
self._ssl_key = cr.load_privatekey(cr.FILETYPE_PEM, ssl_key_pem) |
|
250 |
del cr |
|
251 |
|
|
252 |
ctx.use_privatekey(self._ssl_key) |
|
253 |
ctx.use_certificate(self._ssl_cert) |
|
254 |
ctx.check_privatekey() |
|
255 |
|
|
256 |
if ssl_verify_peer: |
|
257 |
ctx.set_verify(OpenSSL.SSL.VERIFY_PEER | |
|
258 |
OpenSSL.SSL.VERIFY_FAIL_IF_NO_PEER_CERT, |
|
259 |
self._SSLVerifyCallback) |
|
260 |
|
|
261 |
return OpenSSL.SSL.Connection(ctx, sock) |
|
262 |
|
|
263 |
def _SSLVerifyCallback(self, conn, cert, errnum, errdepth, ok): |
|
264 |
"""Verify the certificate provided by the peer |
|
265 |
|
|
266 |
We only compare fingerprints. The client must use the same certificate as |
|
267 |
we do on our side. |
|
268 |
|
|
269 |
""" |
|
270 |
assert self._ssl_cert and self._ssl_key, "SSL not initialized" |
|
271 |
|
|
272 |
return (self._ssl_cert.digest("sha1") == cert.digest("sha1") and |
|
273 |
self._ssl_cert.digest("md5") == cert.digest("md5")) |
|
274 |
|
|
275 |
|
|
212 | 276 |
class _HttpConnectionHandler(object): |
213 | 277 |
"""Implements server side of HTTP |
214 | 278 |
|
... | ... | |
487 | 551 |
logging.debug("HTTP POST data: %s", self.request_post_data) |
488 | 552 |
|
489 | 553 |
|
490 |
class HttpServer(object):
|
|
554 |
class HttpServer(_HttpSocketBase):
|
|
491 | 555 |
"""Generic HTTP server class |
492 | 556 |
|
493 | 557 |
Users of this class must subclass it and override the HandleRequest function. |
... | ... | |
514 | 578 |
it with our certificate |
515 | 579 |
|
516 | 580 |
""" |
581 |
_HttpSocketBase.__init__(self) |
|
582 |
|
|
517 | 583 |
self.mainloop = mainloop |
518 | 584 |
self.local_address = local_address |
519 | 585 |
self.port = port |
520 | 586 |
|
521 |
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) |
|
522 |
|
|
523 |
if ssl_cert_path and ssl_key_path: |
|
524 |
ctx = OpenSSL.SSL.Context(OpenSSL.SSL.SSLv23_METHOD) |
|
525 |
ctx.set_options(OpenSSL.SSL.OP_NO_SSLv2) |
|
526 |
|
|
527 |
ssl_key_pem = utils.ReadFile(ssl_key_path) |
|
528 |
ssl_cert_pem = utils.ReadFile(ssl_cert_path) |
|
529 |
|
|
530 |
cr = OpenSSL.crypto |
|
531 |
self._ssl_cert = cr.load_certificate(cr.FILETYPE_PEM, ssl_cert_pem) |
|
532 |
self._ssl_key = cr.load_privatekey(cr.FILETYPE_PEM, ssl_key_pem) |
|
533 |
del cr |
|
534 |
|
|
535 |
ctx.use_privatekey(self._ssl_key) |
|
536 |
ctx.use_certificate(self._ssl_cert) |
|
537 |
ctx.check_privatekey() |
|
587 |
self.socket = self._CreateSocket(ssl_key_path, ssl_cert_path, ssl_verify_peer) |
|
538 | 588 |
|
539 |
if ssl_verify_peer: |
|
540 |
ctx.set_verify(OpenSSL.SSL.VERIFY_PEER | |
|
541 |
OpenSSL.SSL.VERIFY_FAIL_IF_NO_PEER_CERT, |
|
542 |
self._VerifyCallback) |
|
589 |
# Allow port to be reused |
|
590 |
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) |
|
543 | 591 |
|
544 |
self.socket = OpenSSL.SSL.Connection(ctx, sock)
|
|
592 |
if self._using_ssl:
|
|
545 | 593 |
self._fileio_class = _SSLFileObject |
546 | 594 |
else: |
547 |
self.socket = sock |
|
548 | 595 |
self._fileio_class = socket._fileobject |
549 | 596 |
|
550 |
# Allow port to be reused |
|
551 |
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) |
|
552 |
|
|
553 | 597 |
self._children = [] |
554 | 598 |
|
555 | 599 |
mainloop.RegisterIO(self, self.socket.fileno(), select.POLLIN) |
556 | 600 |
mainloop.RegisterSignal(self) |
557 | 601 |
|
558 |
def _VerifyCallback(self, conn, cert, errno, errdepth, ok): |
|
559 |
"""Verify the certificate provided by the peer |
|
560 |
|
|
561 |
We only compare fingerprints. The client must use the same certificate as |
|
562 |
we do on the server side. |
|
563 |
|
|
564 |
""" |
|
565 |
return (self._ssl_cert.digest("sha1") == cert.digest("sha1") and |
|
566 |
self._ssl_cert.digest("md5") == cert.digest("md5")) |
|
567 |
|
|
568 | 602 |
def Start(self): |
569 | 603 |
self.socket.bind((self.local_address, self.port)) |
570 | 604 |
self.socket.listen(5) |
Also available in: Unified diff