# Path: src/net/tls/common.py
# class TLSError(Exception):
#     """
#     Base class for all TLS/SSL exceptions.
# 
#     Exception args is a message string.
#     """
#     pass
# 
# class TLSProtocolError(TLSError):
#     """
#     Raised when a protocol-related problem occurs, such as the remote end does
#     not speak TLS, or when no shared cipher could be established.
#     """
#     pass
# 
# class TLSVerificationError(TLSError):
#     """
#     Raised when the remote end's certificate did not verify correctly.
#     """
#     pass
# 
# class TLSSocketBase(kaa.Socket):
#     # list of suuported TLS authentication mechanisms (subclass must override)
#     supported_methods = []
#     
#     # Cached system-wide CA cert file (as detected), or None if none was found.
#     _cafile = False
# 
#     __kaasignals__ = {
#         'tls':
#             '''
#             Emitted when a TLS handshake has been successfully completed.
#             '''
#     }
# 
#     def __init__(self, cafile=None):
#         super(TLSSocketBase, self).__init__()
#         self._handshake = False
#         self._pre_handshake_write_queue = []
# 
#         if cafile:
#             self._cafile = cafile
#         elif TLSSocketBase._cafile is False:
#             self._cafile = None
#             for path in CA_SEARCH_PATH:
#                 if os.path.exists(path):
#                     cafile = path
#                     break
#             else:
#                 # Maybe locate(1) can help.
#                 # XXX: assumes this is fast.  Maybe this should be done async.
#                 path = os.popen('locate -l 1 ca-certificates.crt ca-bundle.crt 2>/dev/null').readline().strip()
#                 if os.path.exists(path):
#                     cafile = path
# 
#             TLSSocketBase._cafile = self._cafile = cafile


import logging
import os
import M2Crypto
import kaa
from M2Crypto import m2, X509
from .common import TLSError, TLSProtocolError, TLSVerificationError, TLSSocketBase
    def write(self, data):
        # A write can require us to read from the socket, even when there are
        # no callbacks attached to 'read' or 'readline', such as in the
        # case when a handshake is still pending.  If this is the case,
        # _encrypt() called below will cause _rmon to get registered while
        # the TLS layer needs data from the peer.
        if not self._tls_started:
            return super(M2TLSSocket, self).write(data)

        self._buf_plaintext.append(data)
        try:
            ip = super(M2TLSSocket, self).write(self._encrypt())
            # FIXME: this IP might not reflect the given data for this write()
            # if we're currently doing a handshake.
            return ip
        except M2Crypto.BIO.BIOError, e:
            raise TLSProtocolError(e.args[0])


    def _check(self):
        if self._validated or not m2.ssl_is_init_finished(self._ssl.obj):
            return

        kwargs = self._starttls_kwargs
        if kwargs.get('verify'):
            # See http://www.openssl.org/docs/apps/verify.html#DIAGNOSTICS
            # for the error codes returned by SSL_get_verify_result.
            if m2.ssl_get_verify_result(self._ssl.obj) != m2.X509_V_OK:
                raise TLSVerificationError('Peer certificate is not signed by a known CA')


# Path: src/net/tls/common.py
# class TLSError(Exception):
#     """
#     Base class for all TLS/SSL exceptions.
# 
#     Exception args is a message string.
#     """
#     pass
# 
# class TLSProtocolError(TLSError):
#     """
#     Raised when a protocol-related problem occurs, such as the remote end does
#     not speak TLS, or when no shared cipher could be established.
#     """
#     pass
# 
# class TLSVerificationError(TLSError):
#     """
#     Raised when the remote end's certificate did not verify correctly.
#     """
#     pass
# 
# class TLSSocketBase(kaa.Socket):
#     # list of suuported TLS authentication mechanisms (subclass must override)
#     supported_methods = []
#     
#     # Cached system-wide CA cert file (as detected), or None if none was found.
#     _cafile = False
# 
#     __kaasignals__ = {
#         'tls':
#             '''
#             Emitted when a TLS handshake has been successfully completed.
#             '''
#     }
# 
#     def __init__(self, cafile=None):
#         super(TLSSocketBase, self).__init__()
#         self._handshake = False
#         self._pre_handshake_write_queue = []
# 
#         if cafile:
#             self._cafile = cafile
#         elif TLSSocketBase._cafile is False:
#             self._cafile = None
#             for path in CA_SEARCH_PATH:
#                 if os.path.exists(path):
#                     cafile = path
#                     break
#             else:
#                 # Maybe locate(1) can help.
#                 # XXX: assumes this is fast.  Maybe this should be done async.
#                 path = os.popen('locate -l 1 ca-certificates.crt ca-bundle.crt 2>/dev/null').readline().strip()
#                 if os.path.exists(path):
#                     cafile = path
# 
#             TLSSocketBase._cafile = self._cafile = cafile


# Path: src/net/tls/m2.py
import logging
import os
import M2Crypto
import kaa
from M2Crypto import m2, X509
from .common import TLSError, TLSProtocolError, TLSVerificationError, TLSSocketBase

    def write(self, data):
        # A write can require us to read from the socket, even when there are
        # no callbacks attached to 'read' or 'readline', such as in the
        # case when a handshake is still pending.  If this is the case,
        # _encrypt() called below will cause _rmon to get registered while
        # the TLS layer needs data from the peer.
        if not self._tls_started:
            return super(M2TLSSocket, self).write(data)

        self._buf_plaintext.append(data)
        try:
            ip = super(M2TLSSocket, self).write(self._encrypt())
            # FIXME: this IP might not reflect the given data for this write()
            # if we're currently doing a handshake.
            return ip
        except M2Crypto.BIO.BIOError, e:
            raise TLSProtocolError(e.args[0])


    def _check(self):
        if self._validated or not m2.ssl_is_init_finished(self._ssl.obj):
            return

        kwargs = self._starttls_kwargs
        if kwargs.get('verify'):
            # See http://www.openssl.org/docs/apps/verify.html#DIAGNOSTICS
            # for the error codes returned by SSL_get_verify_result.
            if m2.ssl_get_verify_result(self._ssl.obj) != m2.X509_V_OK:
                raise TLSVerificationError('Peer certificate is not signed by a known CA')


        x509 = self._m2_check_err(m2.ssl_get_peer_cert(self._ssl.obj), TLSVerificationError)