Beispiel #1
0
    def _get_finished_message(self, function):
        """
        Helper to implement :py:meth:`get_finished` and
        :py:meth:`get_peer_finished`.

        :param function: Either :py:data:`SSL_get_finished`: or
            :py:data:`SSL_get_peer_finished`.

        :return: :py:data:`None` if the desired message has not yet been
            received, otherwise the contents of the message.
        :rtype: :py:class:`bytes` or :py:class:`NoneType`
        """
        # The OpenSSL documentation says nothing about what might happen if the
        # count argument given is zero.  Specifically, it doesn't say whether
        # the output buffer may be NULL in that case or not.  Inspection of the
        # implementation reveals that it calls memcpy() unconditionally.
        # Section 7.1.4, paragraph 1 of the C standard suggests that
        # memcpy(NULL, source, 0) is not guaranteed to produce defined (let
        # alone desirable) behavior (though it probably does on just about
        # every implementation...)
        #
        # Allocate a tiny buffer to pass in (instead of just passing NULL as
        # one might expect) for the initial call so as to be safe against this
        # potentially undefined behavior.
        empty = _ffi.new("char[]", 0)
        size = function(self._ssl, empty, 0)
        if size == 0:
            # No Finished message so far.
            return None

        buf = _ffi.new("char[]", size)
        function(self._ssl, buf, size)
        return _ffi.buffer(buf, size)[:]
Beispiel #2
0
    def _get_finished_message(self, function):
        """
        Helper to implement :py:meth:`get_finished` and
        :py:meth:`get_peer_finished`.

        :param function: Either :py:data:`SSL_get_finished`: or
            :py:data:`SSL_get_peer_finished`.

        :return: :py:data:`None` if the desired message has not yet been
            received, otherwise the contents of the message.
        :rtype: :py:class:`bytes` or :py:class:`NoneType`
        """
        # The OpenSSL documentation says nothing about what might happen if the
        # count argument given is zero.  Specifically, it doesn't say whether
        # the output buffer may be NULL in that case or not.  Inspection of the
        # implementation reveals that it calls memcpy() unconditionally.
        # Section 7.1.4, paragraph 1 of the C standard suggests that
        # memcpy(NULL, source, 0) is not guaranteed to produce defined (let
        # alone desirable) behavior (though it probably does on just about
        # every implementation...)
        #
        # Allocate a tiny buffer to pass in (instead of just passing NULL as
        # one might expect) for the initial call so as to be safe against this
        # potentially undefined behavior.
        empty = _ffi.new("char[]", 0)
        size = function(self._ssl, empty, 0)
        if size == 0:
            # No Finished message so far.
            return None

        buf = _ffi.new("char[]", size)
        function(self._ssl, buf, size)
        return _ffi.buffer(buf, size)[:]
Beispiel #3
0
    def master_key(self):
        """
        Get a copy of the master key.

        :return: A string representing the state
        """
        if self._ssl.session == _ffi.NULL:
            return None
        return _ffi.buffer(self._ssl.session.master_key,
                           self._ssl.session.master_key_length)[:]
Beispiel #4
0
    def client_random(self):
        """
        Get a copy of the client hello nonce.

        :return: A string representing the state
        """
        if self._ssl.session == _ffi.NULL:
            return None
        return _ffi.buffer(self._ssl.s3.client_random,
                           _lib.SSL3_RANDOM_SIZE)[:]
Beispiel #5
0
    def master_key(self):
        """
        Get a copy of the master key.

        :return: A string representing the state
        """
        if self._ssl.session == _ffi.NULL:
            return None
        return _ffi.buffer(
            self._ssl.session.master_key,
            self._ssl.session.master_key_length)[:]
Beispiel #6
0
    def client_random(self):
        """
        Get a copy of the client hello nonce.

        :return: A string representing the state
        """
        if self._ssl.session == _ffi.NULL:
            return None
        return _ffi.buffer(
            self._ssl.s3.client_random,
            _lib.SSL3_RANDOM_SIZE)[:]
Beispiel #7
0
    def recv(self, bufsiz, flags=None):
        """
        Receive data on the connection. NOTE: If you get one of the WantRead,
        WantWrite or WantX509Lookup exceptions on this, you have to call the
        method again with the SAME buffer.

        :param bufsiz: The maximum number of bytes to read
        :param flags: (optional) Included for compatibility with the socket
                      API, the value is ignored
        :return: The string read from the Connection
        """
        buf = _ffi.new("char[]", bufsiz)
        result = _lib.SSL_read(self._ssl, buf, bufsiz)
        self._raise_ssl_error(self._ssl, result)
        return _ffi.buffer(buf, result)[:]
Beispiel #8
0
    def recv(self, bufsiz, flags=None):
        """
        Receive data on the connection. NOTE: If you get one of the WantRead,
        WantWrite or WantX509Lookup exceptions on this, you have to call the
        method again with the SAME buffer.

        :param bufsiz: The maximum number of bytes to read
        :param flags: (optional) Included for compatibility with the socket
                      API, the value is ignored
        :return: The string read from the Connection
        """
        buf = _ffi.new("char[]", bufsiz)
        result = _lib.SSL_read(self._ssl, buf, bufsiz)
        self._raise_ssl_error(self._ssl, result)
        return _ffi.buffer(buf, result)[:]
Beispiel #9
0
    def bio_read(self, bufsiz):
        """
        When using non-socket connections this function reads the "dirty" data
        that would have traveled away on the network.

        :param bufsiz: The maximum number of bytes to read
        :return: The string read.
        """
        if self._from_ssl is None:
            raise TypeError("Connection sock was not None")

        if not isinstance(bufsiz, integer_types):
            raise TypeError("bufsiz must be an integer")

        buf = _ffi.new("char[]", bufsiz)
        result = _lib.BIO_read(self._from_ssl, buf, bufsiz)
        if result <= 0:
            self._handle_bio_errors(self._from_ssl, result)

        return _ffi.buffer(buf, result)[:]
Beispiel #10
0
    def bio_read(self, bufsiz):
        """
        When using non-socket connections this function reads the "dirty" data
        that would have traveled away on the network.

        :param bufsiz: The maximum number of bytes to read
        :return: The string read.
        """
        if self._from_ssl is None:
            raise TypeError("Connection sock was not None")

        if not isinstance(bufsiz, integer_types):
            raise TypeError("bufsiz must be an integer")

        buf = _ffi.new("char[]", bufsiz)
        result = _lib.BIO_read(self._from_ssl, buf, bufsiz)
        if result <= 0:
            self._handle_bio_errors(self._from_ssl, result)

        return _ffi.buffer(buf, result)[:]
Beispiel #11
0
def bytes(num_bytes):
    """
    Get some random bytes as a string.

    :param num_bytes: The number of bytes to fetch
    :return: A string of random bytes
    """
    if not isinstance(num_bytes, _integer_types):
        raise TypeError("num_bytes must be an integer")

    if num_bytes < 0:
        raise ValueError("num_bytes must not be negative")

    result_buffer = _ffi.new("char[]", num_bytes)
    result_code = _lib.RAND_bytes(result_buffer, num_bytes)
    if result_code == -1:
        # TODO: No tests for this code path.  Triggering a RAND_bytes failure
        # might involve supplying a custom ENGINE?  That's hard.
        _raise_current_error()

    return _ffi.buffer(result_buffer)[:]
Beispiel #12
0
def bytes(num_bytes):
    """
    Get some random bytes as a string.

    :param num_bytes: The number of bytes to fetch
    :return: A string of random bytes
    """
    if not isinstance(num_bytes, _integer_types):
        raise TypeError("num_bytes must be an integer")

    if num_bytes < 0:
        raise ValueError("num_bytes must not be negative")

    result_buffer = _ffi.new("char[]", num_bytes)
    result_code = _lib.RAND_bytes(result_buffer, num_bytes)
    if result_code == -1:
        # TODO: No tests for this code path.  Triggering a RAND_bytes failure
        # might involve supplying a custom ENGINE?  That's hard.
        _raise_current_error()

    return _ffi.buffer(result_buffer)[:]