Ejemplo n.º 1
0
 def write_some(self, data):
     """See :meth:`versile.reactor.io.IVByteOutput.write_some`\ ."""
     if not self.was_connected:
         raise VIOError('Socket not connected')
     if self._sock_out_closed:
         if isinstance(self._sock_out_closed_reason, VFIOCompleted):
             raise VIOCompleted()
         else:
             raise VIOLost()
     if not self.sock:
         raise VIOError('No socket')
     try:
         if _pyver == 2:
             num_written = self.sock.send(_b2s(data))
         else:
             num_written = self.sock.send(data)
     except IOError as e:
         if e.errno in _errno_block:
             return 0
         elif (e.errno in (errno.EPIPE, errno.ENOTCONN)
               and not self._sock_verified):
             # ISSUE - these have been seen to be raised after
             # socket thinks it is connected due to select() event,
             # however ignoring it causes the connection to be
             # 'resumed'. For now we log a message and resume.
             self.log.debug('Ignoring post-connect write errno %s' %
                            e.errno)
             return 0
         else:
             self.log.debug('Write got errno %s' % e.errno)
             raise VIOError('Socket write error, errno %s' % e.errno)
     else:
         self._sock_verified = True
         return num_written
Ejemplo n.º 2
0
 def __fmt(self, fmt):
     with self:
         result = [self._str_prefix()]
         index = [0] * len(self._dim)
         first = True
         while True:
             if not first:
                 if _pyver == 2:
                     result.append(b', ')
                 else:
                     result.append(', ')
             first = False
             if _pyver == 2:
                 result.append(b'%s: %s' % (tuple(index), fmt(self[index])))
             else:
                 result.append('%s: %s' % (tuple(index), fmt(self[index])))
             for i in xrange(len(index)):
                 index[i] += 1
                 if index[i] < self._dim[i]:
                     break
                 else:
                     index[i] = 0
             else:
                 break
         if _pyver == 2:
             result.append(b']')
         else:
             result.append(']')
     if _pyver == 2:
         return (_b2s(b''.join(result)))
     else:
         return ''.join(result)
Ejemplo n.º 3
0
    def __init__(self, daemon=False):
        super(VFDWaitReactor, self).__init__()
        if daemon:
            self.daemon = True
        self.name = 'VSelectReactor-' + str(self.name.split('-')[1])

        self.__readers, self.__writers = set(), set()

        self.__finished = False
        self.__thread = None

        if _vplatform == 'ironpython' or sys.platform == _b2s(b'win32'):
            self.__ctrl_is_pipe = False
            from versile.reactor.io.tcp import VTCPSocket
            self.__ctrl_r, self.__ctrl_w = VTCPSocket.create_native_pair()
        else:
            self.__ctrl_is_pipe = True
            self.__ctrl_r, self.__ctrl_w = os.pipe()
        self.__ctrl_queue = deque()
        self.__ctrl_msg_flag = False
        self.__ctrl_stop = False
        # Locks __ctrl_msg_flag, __ctrl_queue, writing to __ctrl_w
        self.__ctrl_lock = threading.Lock()

        self.__scheduled_calls = []          # heapq-ordered list
        self.__grouped_calls = {}
        self.__calls_lock = threading.Lock() # Locks scheduled/grouped calls
        self.__t_next_call = None            # Timestamp next call (or None)

        self.__core_log = VLogger()
        self.__logger = VReactorLogger(self)
        self.__logger.add_watcher(self.__core_log)
        # Reactor-only proxy logger which adds a prefix
        self.__rlog = self.__core_log.create_proxy_logger(prefix='Reactor')
Ejemplo n.º 4
0
    def export_spki_public_key(cls, key, fmt=VX509Format.PEM_BLOCK):
        """Exports a X.509 SPKI public key.

        :param key: key to export
        :type  key: :class:`versile.crypto.VAsymmetricKey`
        :param fmt: format to export to
        :type  fmt: :class:`VX509Format` constant
        :returns:   exported key data

        Exports an encoding of the key's :term:`ASN.1` representation
        defined by X.509 SubjectPublicKeyInfo encoding format,
        associated with the PEM header 'BEGIN PUBLIC KEY'.

        .. note::

            For the :term:`PKCS#1`\ encoding format (PEM header 'BEGIN
            RSA PUBLIC KEY'), see :meth:`export_public_key`\ .

        """
        if not isinstance(key, VAsymmetricKey):
            raise TypeError('Invalid key type')
        if key.cipher_name != 'rsa':
            raise VCryptoException('Encoding not supported')
        if key.has_public:
            n, e = key.keydata[:2]

            # Create spki structure
            from versile.crypto.x509.asn1def.cert import SubjectPublicKeyInfo
            asn1 = SubjectPublicKeyInfo().create()
            # - algorithm
            alg = AlgorithmIdentifier().create()
            _alg_id = VObjectIdentifier(1, 2, 840, 113549, 1, 1, 1)
            alg.append(_alg_id, name='algorithm')
            alg.append(VASN1Null(), name='parameters')
            asn1.append(alg, name='algorithm')
            # - keydata
            spk = cls.export_public_key(key, fmt=VX509Format.DER)
            spk = VBitfield.from_octets(spk)
            asn1.append(spk, name='subjectPublicKey')

            if not asn1.validate():
                raise VCryptoException('ASN.1 structure validation error')

            if fmt == VX509Format.ASN1:
                return asn1
            der = asn1.encode_der()
            if fmt == VX509Format.DER:
                return der
            if fmt == VX509Format.PEM:
                if _pyver == 2:
                    return _s2b(base64.encodestring(_b2s(der)))
                else:
                    return base64.encodebytes(der)
            elif fmt == VX509Format.PEM_BLOCK:
                return encode_pem_block(b'PUBLIC KEY', der)
            else:
                raise VCryptoException('Invalid encoding')
Ejemplo n.º 5
0
    def number(self, min_num, max_num):
        """Returns an integer constructed from generated byte data.

        :param min_num: lowest integer to produce
        :type  min_num: int, long
        :param max_num: highest integer to produce
        :type  max_num: int, long
        :returns:       number with min_num <= num <= max_num
        :rtype:         int, long

        The method will internally call :meth:`data` to generate data
        to create the output number.

        .. warning::

            The method may need to generate multiple iterations of
            byte data until a number can be constructed. If generated
            bytes do not appear 'random' (such as e.g. a constant byte
            value generator), this method may never return.

        """
        if min_num == max_num:
            return min_num
        diff = max_num - min_num
        diff_hex = _s2b(hex(diff)).lstrip(b'0x').rstrip(b'L')
        if len(diff_hex) % 2:
            diff_hex = b'0' + diff_hex
        num_bytes = len(diff_hex) // 2
        # Create a mask for the left zero bytes
        left_byte = int(_b2s(b'0x' + diff_hex[:2]), 16)
        mask = 0xff
        for i in xrange(7, -1, -1):
            bit = 0x01 << i
            if left_byte & bit:
                break
            else:
                mask = mask ^ bit
        while True:
            data = self(num_bytes)
            data_chars = [_s2b('0x')]
            first = True
            for d in data:
                b = _b_ord(d)
                if first:
                    b &= mask
                    first = False
                _chars = hex((b >> 4) & 0xf)[-1] + hex(b & 0xf)[-1]
                data_chars.append(_s2b(_chars))
            data_hex = _s2b('').join(data_chars)
            num = long(data_hex, 16)
            if num <= diff:
                break
        return min_num + num
Ejemplo n.º 6
0
    def __msg_push(self, code, data):
        """Push internal message onto msg queue and interrupts event loop."""
        if self.__finished:
            # Not accepting messages if reactor has finished
            return

        self.__ctrl_lock.acquire()
        try:
            self.__ctrl_queue.append((code, data))
            if not self.__ctrl_msg_flag:
                if _pyver == 2:
                    if self.__ctrl_is_pipe:
                        os.write(self.__ctrl_w, _b2s(b'x'))
                    else:
                        self.__ctrl_w.send(_b2s(b'x'))
                else:
                    if self.__ctrl_is_pipe:
                        os.write(self.__ctrl_w, b'x')
                    else:
                        self.__ctrl_w.send(b'x')
                self.__ctrl_msg_flag = True
        finally:
            self.__ctrl_lock.release()
Ejemplo n.º 7
0
    def export_public_key(cls, key, fmt=VX509Format.PEM_BLOCK):
        """Exports a public key in PKCS#1 format.

        :param key: key to export
        :type  key: :class:`versile.crypto.VAsymmetricKey`
        :param fmt: format to export to
        :type  fmt: :class:`VX509Format` constant
        :returns:   exported key data

        Exports an encoding of the key's :term:`ASN.1` representation
        defined by :term:`PKCS#1`\, associated with the PEM header
        'BEGIN RSA PUBLIC KEY'.

        .. note::

            For the X.509 SubjectPublicKeyInfo encoding format (PEM
            header 'BEGIN PUBLIC KEY'), see
            :meth:`export_spki_public_key`\ .

        """
        if not isinstance(key, VAsymmetricKey):
            raise TypeError('Invalid key type')
        if key.cipher_name == 'rsa':
            if key.has_public:
                n, e = key.keydata[:2]

                asn1 = RSAPublicKey().create()
                asn1.append(n, name='modulus')
                asn1.append(e, name='publicExponent')
                if not asn1.validate():
                    raise VCryptoException('ASN.1 structure validation error')

                if fmt == VX509Format.ASN1:
                    return asn1
                der = asn1.encode_der()
                if fmt == VX509Format.DER:
                    return der
                if fmt == VX509Format.PEM:
                    if _pyver == 2:
                        return _s2b(base64.encodestring(_b2s(der)))
                    else:
                        return base64.encodebytes(der)
                elif fmt == VX509Format.PEM_BLOCK:
                    return encode_pem_block(b'RSA PUBLIC KEY', der)
                else:
                    raise VCryptoException('Invalid encoding')
        else:
            raise VCryptoException('Encoding not supported')
Ejemplo n.º 8
0
    def _encode_ascii(self, name, numbers):
        """Internal convenience method for exporting as ASCII.

        :param name:    cipher name
        :type  name:    unicode
        :param numbers: keydata number components
        :type  numbers: list<int>

        Can be used internally by implementations of derived classes.

        """
        header = b'-----BEGIN ' + name + b'-----\n'
        footer = b'-----END ' + name + b'-----\n'
        num_data = b''.join([posint_to_netbytes(i) for i in numbers])
        if _pyver == 2:
            num_data = _s2b(base64.encodestring(_b2s(num_data)))
        else:
            num_data = base64.encodebytes(num_data)
        data = b''.join((header, num_data, footer))
        data = b'\r\n'.join(data.split(b'\n'))
        return data
Ejemplo n.º 9
0
 def write_some(self, data):
     """See :meth:`versile.reactor.io.IVByteOutput.write_some`\ ."""
     if self._out_closed:
         if isinstance(self._out_closed_reason, VFIOCompleted):
             raise VIOCompleted()
         else:
             raise VIOLost()
     try:
         if _pyver == 2:
             data = _b2s(data)
         num_written = os.write(self._fd, data)
     except OSError as e:
         if e.errno in _errno_block:
             return 0
         else:
             self.log.debug('Write got errno %s' % e.errno)
             raise VIOError('Pipe read error')
     else:
         if num_written > 0:
             return num_written
         else:
             self.log.debug('Pipe write error')
             raise VIOError('Pipe write error')
Ejemplo n.º 10
0
    def _decode_ascii(cls, block):
        """Decodes an ASCII block.

        :param block: standard ASCII block representation
        :type  block: bytes
        :returns:     (block_name, block_data)
        :raises:      VCryptoException

        Internal convenience method for derived classes implementing
        ascii key import.

        """
        block = block.strip()
        m = re.match(b'-----BEGIN ', block)
        if not m:
            raise VCryptoException()
        block = block[m.end():]
        m = re.search(b'-----', block)
        if not m:
            raise VCryptoException()
        block_name = block[:m.start()]
        block = block[m.end():]
        block = block.strip()
        end = b'-----END ' + block_name + b'-----'
        if not block.endswith(end):
            raise VCryptoException()
        block = block[:(-len(end))]
        try:
            if _pyver == 2:
                decoded = _s2b(base64.decodestring(_b2s(block)))
            else:
                decoded = base64.decodebytes(block)
        except:
            raise VCryptoException()
        else:
            return (block_name, decoded)
Ejemplo n.º 11
0
    def import_spki_public_key(cls,
                               data,
                               fmt=VX509Format.PEM_BLOCK,
                               keytype='rsa',
                               crypto=None):
        """Imports a X.509 SPKI public key.

        :param data:    keydata to import
        :param fmt:     format to import from
        :type  fmt:     :class:`VX509Format` constant
        :param keytype: key type to import (or None)
        :param keytype: unicode
        :param crypto:  crypto provider (default if None)
        :type  crypto:  :class:`versile.crypto.VCrypto`
        :returns:       imported key
        :rtype:         :class:`versile.crypto.VAsymmetricKey`

        Imports an encoding of the key's :term:`ASN.1` representation
        defined by X.509 SubjectPublicKeyInfo encoding format,
        associated with the PEM header 'BEGIN PUBLIC KEY'.

        .. note::

            For the :term:`PKCS#1`\ encoding format (PEM header 'BEGIN
            RSA PUBLIC KEY'), see :meth:`import_public_key`\ .

        """
        crypto = VCrypto.lazy(crypto)
        if fmt == VX509Format.PEM_BLOCK:
            heading, data = decode_pem_block(data)
            if heading == b'PUBLIC KEY':
                if keytype is None:
                    keytype = 'rsa'
                elif keytype != 'rsa':
                    raise VCryptoException('Key type mismatch')
            else:
                raise VCryptoException('Key type not supported')
            fmt = VX509Format.DER
        elif fmt == VX509Format.PEM:
            if keytype != 'rsa':
                raise VCryptoException('Key type not supported')
            if _pyver == 2:
                data = _s2b(base64.decodestring(_b2s(data)))
            else:
                data = base64.decodebytes(data)
            fmt = VX509Format.DER
        if fmt == VX509Format.DER:
            from versile.crypto.x509.asn1def.cert import SubjectPublicKeyInfo
            spki, len_read = SubjectPublicKeyInfo().parse_der(data)
            if len_read != len(data):
                raise VCryptoException('Public Key DER data overflow')
            data = spki
            fmt = VX509Format.ASN1
        if fmt == VX509Format.ASN1:
            if keytype != 'rsa':
                raise VCryptoException('Key type not supported')
            spki = data.native(deep=True)
            _alg, keydata = spki

            # Verify supported key type
            alg, _params = _alg
            if alg != VObjectIdentifier(1, 2, 840, 113549, 1, 1, 1):
                raise VCryptoException('Unsupported key algorithm')

            # Import key from embedded DER data
            pub_key = cls.import_public_key(keydata.as_octets(),
                                            VX509Format.DER)
            return pub_key
Ejemplo n.º 12
0
    def import_private_key(cls,
                           data,
                           fmt=VX509Format.PEM_BLOCK,
                           keytype='rsa',
                           crypto=None):
        """Imports a PKCS#1 private key (i.e. a complete keypair).

        :param data:    keydata to import
        :param fmt:     format to import from
        :type  fmt:     :class:`VX509Format` constant
        :param keytype: key type to import (or None)
        :param keytype: unicode
        :param crypto:  crypto provider (default if None)
        :type  crypto:  :class:`versile.crypto.VCrypto`
        :returns:       imported key
        :rtype:         :class:`versile.crypto.VAsymmetricKey`

        Imports an encoding of the key's :term:`ASN.1` representation
        defined by :term:`PKCS#1`\, associated with the PEM header
        'BEGIN RSA PRIVATE KEY'.

        .. note::

            Whereas :term:`VPy` refers to complete keys as 'key
            pairs' and private keys as only the private component of
            the key, private keys in :term:`PKCS#1` refer to the
            complete key - thus the naming convention for this method.

        .. note::

            Importing from the PKCS#8 PrivateKeyInfo encoding format
            (PEM header 'BEGIN PRIVATE KEY') is not supported.

        """
        crypto = VCrypto.lazy(crypto)
        if fmt == VX509Format.PEM_BLOCK:
            heading, data = decode_pem_block(data)
            if heading == b'RSA PRIVATE KEY':
                if keytype is None:
                    keytype = 'rsa'
                elif keytype != 'rsa':
                    raise VCryptoException('Key type mismatch')
            else:
                raise VCryptoException('Key type not supported')
            fmt = VX509Format.DER
        elif fmt == VX509Format.PEM:
            if keytype != 'rsa':
                raise VCryptoException('Key type not supported')
            if _pyver == 2:
                data = _s2b(base64.decodestring(_b2s(data)))
            else:
                data = base64.decodebytes(data)
            fmt = VX509Format.DER
        if fmt == VX509Format.DER:
            asn1key, len_read = RSAPrivateKey().parse_der(data)
            if len_read != len(data):
                raise VCryptoException('Public Key DER data overflow')
            data = asn1key
            fmt = VX509Format.ASN1
        if fmt == VX509Format.ASN1:
            if keytype != 'rsa':
                raise VCryptoException('Key type not supported')
            data = data.native(deep=True)
            version, n, e, d, p, q, exp1, exp2, coeff = data[:9]
            for _param in (e, d, p, q, exp1, exp2, coeff):
                if not 0 < _param < n:
                    raise VCryptoException('Invalid key parameter(s)')
            key_params = (n, e, d, p, q)
            return crypto.num_rsa.key_factory.load(key_params)
Ejemplo n.º 13
0
    def import_public_key(cls,
                          data,
                          fmt=VX509Format.PEM_BLOCK,
                          keytype='rsa',
                          crypto=None):
        """Imports a PKCS#1 public key.

        :param data:    keydata to import
        :param fmt:     format to import from
        :type  fmt:     :class:`VX509Format` constant
        :param keytype: key type to import (or None)
        :param keytype: unicode
        :param crypto:  crypto provider (default if None)
        :type  crypto:  :class:`versile.crypto.VCrypto`
        :returns:       imported key
        :rtype:         :class:`versile.crypto.VAsymmetricKey`

        Imports an encoding of the key's :term:`ASN.1` representation
        defined by :term:`PKCS#1`\, associated with the PEM header
        'BEGIN RSA PUBLIC KEY'.

        .. note::

            For the X.509 SubjectPublicKeyInfo encoding format (PEM
            header 'BEGIN PUBLIC KEY'), see
            :meth:`import_spki_public_key`\ .

        """
        crypto = VCrypto.lazy(crypto)
        if fmt == VX509Format.PEM_BLOCK:
            heading, data = decode_pem_block(data)
            if heading == b'RSA PUBLIC KEY':
                if keytype is None:
                    keytype = 'rsa'
                elif keytype != 'rsa':
                    raise VCryptoException('Key type mismatch')
            else:
                raise VCryptoException('Key type not supported')
            fmt = VX509Format.DER
        elif fmt == VX509Format.PEM:
            if keytype != 'rsa':
                raise VCryptoException('Key type not supported')
            if _pyver == 2:
                data = _s2b(base64.decodestring(_b2s(data)))
            else:
                data = base64.decodebytes(data)
            fmt = VX509Format.DER
        if fmt == VX509Format.DER:
            asn1key, len_read = RSAPublicKey().parse_der(data)
            if len_read != len(data):
                raise VCryptoException('Public Key DER data overflow')
            data = asn1key
            fmt = VX509Format.ASN1
        if fmt == VX509Format.ASN1:
            if keytype != 'rsa':
                raise VCryptoException('Key type not supported')
            n = data.modulus.native()
            e = data.publicExponent.native()
            if not 0 < e < n:
                raise VCryptoException('Invalid key parameters')
            key_params = (n, e, None, None, None)
            return crypto.num_rsa.key_factory.load(key_params)
Ejemplo n.º 14
0
    def export_private_key(cls, key, fmt=VX509Format.PEM_BLOCK):
        """Exports a private key (complete keypair) as PKCS#1.

        :param key: key to export
        :type  key: :class:`versile.crypto.VAsymmetricKey`
        :param fmt: format to export to
        :type  fmt: :class:`VX509Format` constant
        :returns:   exported key data

        Exports an encoding of the key's :term:`ASN.1` representation
        defined by :term:`PKCS#1`\, associated with the PEM header
        'BEGIN RSA PRIVATE KEY'.

        .. note::

            Whereas :term:`VPy` refers to complete keys as 'key
            pairs' and private keys as only the private component of
            the key, private keys in :term:`PKCS#1` refer to the
            complete key - thus the naming convention for this method.

        .. note::

            Exporting to the PKCS#8 key format (PEM header 'BEGIN
            PRIVATE KEY') is not supported.

        """
        if not isinstance(key, VAsymmetricKey):
            raise TypeError('Invalid key type')
        if key.cipher_name == 'rsa':
            if key.has_private:
                n, e, d, p, q = key.keydata
                params = (0, n, e, d, p, q, key._exp1, key._exp2, key._coeff)
                if None in params:
                    raise VCryptoException(
                        'X.509 parameters missing from key.')

                asn1 = RSAPrivateKey().create()
                asn1.append(0, name='version')
                asn1.append(n, name='modulus')
                asn1.append(e, name='publicExponent')
                asn1.append(d, name='privateExponent')
                asn1.append(p, name='prime1')
                asn1.append(q, name='prime2')
                asn1.append(key._exp1, name='exponent1')
                asn1.append(key._exp2, name='exponent2')
                asn1.append(key._coeff, name='coefficient')
                if not asn1.validate():
                    raise VCryptoException('ASN.1 structure validation error')

                if fmt == VX509Format.ASN1:
                    return asn1
                der = asn1.encode_der()
                if fmt == VX509Format.DER:
                    return der
                if fmt == VX509Format.PEM:
                    if _pyver == 2:
                        return _s2b(base64.encodestring(_b2s(der)))
                    else:
                        return base64.encodebytes(der)
                elif fmt == VX509Format.PEM_BLOCK:
                    return encode_pem_block(b'RSA PRIVATE KEY', der)
                else:
                    raise VCryptoException('Invalid encoding')
        else:
            raise VCryptoException('Encoding not supported')
Ejemplo n.º 15
0
from versile.reactor.io import VIOCompleted, VIOLost, VIOError, VIOException
from versile.reactor.io import VFIOCompleted, VFIOLost, IVByteIO
from versile.reactor.io import IVSelectable, IVSelectableIO, IVByteInput
from versile.reactor.io import IVByteProducer, IVByteConsumer
from versile.reactor.io import VHalfClose, VNoHalfClose
from versile.reactor.io import VIOControl, VIOMissingControl
from versile.reactor.io.descriptor import IVDescriptor

__all__ = [
    'IVClientSocket', 'IVSocket', 'VClientSocket', 'VClientSocketAgent',
    'VClientSocketFactory', 'VListeningSocket', 'VSocket', 'VSocketBase'
]
__all__ = _vexport(__all__)

# Workaround for Windows-specific error codes
if sys.platform == _b2s(b'win32') or _vplatform == 'ironpython':
    _errno_block = (errno.EWOULDBLOCK, errno.WSAEWOULDBLOCK)
    _errno_connect = (errno.EINPROGRESS, errno.WSAEWOULDBLOCK)
else:
    _errno_block = (errno.EWOULDBLOCK, )
    _errno_connect = (errno.EINPROGRESS, )


class IVSocket(IVDescriptor, IVSelectable):
    """Interface for a general socket descriptor."""
    @classmethod
    def create_native(cls):
        """Creates a native socket.

        :returns: :class:`socket.socket`
Ejemplo n.º 16
0
 def update(self, data):
     if _pyver == 2:
         self.__hash.update(_b2s(data))
     else:
         self.__hash.update(data)