예제 #1
0
 def _ssl_handshake(self):
     """
     Perform an SSL handshake w/ the server.
     Precondition: a successful STARTTLS exchange has
                  taken place with Riak
     returns True upon success, otherwise an exception is raised
     """
     credentials = self._client._credentials
     if credentials:
         try:
             ssl_ctx = configure_ssl_context(credentials)
             host = self._address[0]
             ssl_socket = ssl.SSLSocket(
                 sock=self._socket,
                 keyfile=credentials.pkey_file,
                 certfile=credentials.cert_file,
                 cert_reqs=ssl.CERT_REQUIRED,
                 ca_certs=credentials.cacert_file,
                 ciphers=credentials.ciphers,
                 server_hostname=host)
             ssl_socket.context = ssl_ctx
             # ssl handshake successful
             ssl_socket.do_handshake()
             self._socket = ssl_socket
             return True
         except ssl.SSLError as e:
             raise SecurityError(e)
         except Exception as e:
             # fail if *any* exceptions are thrown during SSL handshake
             raise SecurityError(e)
예제 #2
0
 def _init_security(self):
     """
     Initialize a secure connection to the server.
     """
     if not self._starttls():
         raise SecurityError("Could not start TLS connection")
     # _ssh_handshake() will throw an exception upon failure
     self._ssl_handshake()
     if not self._auth():
         raise SecurityError("Could not authorize connection")
예제 #3
0
    def configure_ssl_context(credentials):
        """
        Set various options on the SSL context for Python >= 2.7.9 and 3.x.

        N.B. versions earlier than 3.4 may not support all security
        measures, e.g., hostname check.

        :param credentials: Riak Security Credentials
        :type credentials: :class:`~riak.security.SecurityCreds`
        :rtype :class:`~ssl.SSLContext`
        """

        ssl_ctx = ssl.SSLContext(credentials.ssl_version)
        ssl_ctx.verify_mode = ssl.CERT_REQUIRED
        if hasattr(ssl_ctx, 'check_hostname'):
            ssl_ctx.check_hostname = True
        if credentials.cacert_file is None:
            raise SecurityError("cacert_file is required in SecurityCreds")
        if credentials.ciphers is not None:
            ssl_ctx.set_ciphers(credentials.ciphers)

        ssl_ctx.load_verify_locations(credentials.cacert_file)
        if credentials.ciphers is not None:
            ssl_ctx.set_ciphers(credentials.ciphers)

        pkeyfile = credentials.pkey_file
        certfile = credentials.cert_file
        if pkeyfile and not certfile:
            raise SecurityError("cert_file must be specified with pkey_file")
        if certfile and not pkeyfile:
            pkeyfile = certfile
        if certfile:
            ssl_ctx.load_cert_chain(certfile, pkeyfile)
        # TODO https://bugs.python.org/issue8813
        if credentials.crl_file is not None:
            ssl_ctx.load_verify_locations(credentials.crl_file)
            ssl_ctx.verify_flags = ssl.VERIFY_CRL_CHECK_LEAF

        # SSLv2 considered harmful.
        ssl_ctx.options |= ssl.OP_NO_SSLv2

        # SSLv3 has problematic security and is only required for really old
        # clients such as IE6 on Windows XP
        ssl_ctx.options |= ssl.OP_NO_SSLv3

        # disable compression to prevent CRIME attacks (OpenSSL 1.0+)
        ssl_ctx.options |= ssl.OP_NO_COMPRESSION

        return ssl_ctx
예제 #4
0
    def connect(self):
        """
        Connect to a host on a given (SSL) port using PyOpenSSL.
        """
        sock = socket.create_connection((self.host, self.port), self.timeout)
        if PY2:
            ssl_ctx = configure_pyopenssl_context(self.credentials)

            # attempt to upgrade the socket to TLS
            cxn = OpenSSL.SSL.Connection(ssl_ctx, sock)
            cxn.set_connect_state()
            while True:
                try:
                    cxn.do_handshake()
                except OpenSSL.SSL.WantReadError:
                    select.select([sock], [], [])
                    continue
                except OpenSSL.SSL.Error as e:
                    raise SecurityError('bad handshake - ' + str(e))
                break

            self.sock = RiakWrappedSocket(cxn, sock)
            self.credentials._check_revoked_cert(self.sock)
        else:
            ssl_ctx = configure_ssl_context(self.credentials)
            host = "riak@" + self.host
            self.sock = ssl.SSLSocket(sock=sock,
                                      keyfile=self.credentials.pkey_file,
                                      certfile=self.credentials.cert_file,
                                      cert_reqs=ssl.CERT_REQUIRED,
                                      ca_certs=self.credentials.cacert_file,
                                      ciphers=self.credentials.ciphers,
                                      server_hostname=host)
            self.sock.context = ssl_ctx
예제 #5
0
    def _ssl_handshake(self):
        """
        Perform an SSL handshake w/ the server.
        Precondition: a successful STARTTLS exchange has
                     taken place with Riak
        returns True upon success, otherwise an exception is raised
        """
        if self._client._credentials:
            ssl_ctx = \
                Context(self._client._credentials.ssl_version)
            try:
                configure_context(ssl_ctx, self._client._credentials)
                # attempt to upgrade the socket to SSL
                ssl_socket = Connection(ssl_ctx, self._socket)
                ssl_socket.set_connect_state()
                ssl_socket.do_handshake()
                # ssl handshake successful
                self._socket = ssl_socket

                self._client._credentials._check_revoked_cert(ssl_socket)

                return True
            except Exception as e:
                # fail if *any* exceptions are thrown during SSL handshake
                raise SecurityError(e.message)
예제 #6
0
    def configure_pyopenssl_context(credentials):
        """
        Set various options on the SSL context for Python <= 2.7.8.

        :param credentials: Riak Security Credentials
        :type credentials: :class:`~riak.security.SecurityCreds`
        :rtype ssl_ctx: :class:`~OpenSSL.SSL.Context`
        """

        ssl_ctx = OpenSSL.SSL.Context(credentials.ssl_version)
        if credentials._has_credential('pkey'):
            ssl_ctx.use_privatekey(credentials.pkey)
        if credentials._has_credential('cert'):
            ssl_ctx.use_certificate(credentials.cert)
        if credentials._has_credential('cacert'):
            store = ssl_ctx.get_cert_store()
            cacerts = credentials.cacert
            if not isinstance(cacerts, list):
                cacerts = [cacerts]
            for cacert in cacerts:
                store.add_cert(cacert)
        else:
            raise SecurityError("cacert_file is required in SecurityCreds")
        ciphers = credentials.ciphers
        if ciphers is not None:
            ssl_ctx.set_cipher_list(ciphers)
        # Demand a certificate
        ssl_ctx.set_verify(
            OpenSSL.SSL.VERIFY_PEER | OpenSSL.SSL.VERIFY_FAIL_IF_NO_PEER_CERT,
            verify_cb)
        return ssl_ctx
예제 #7
0
def verify_cb(conn, cert, errnum, depth, ok):
    """
    The default OpenSSL certificate verification callback.
    """
    if not ok:
        raise SecurityError("Could not verify CA certificate {0}".format(
            cert.get_subject()))
    return ok
    def set_bucket_props(self, bucket, props):
        """
        Set the properties on the bucket object given
        """
        bucket_type = self._get_bucket_type(bucket.bucket_type)
        url = self.bucket_properties_path(bucket.name, bucket_type=bucket_type)
        headers = {'Content-Type': 'application/json'}
        content = json.dumps({'props': props})

        # Run the request...
        status, _, body = self._request('PUT', url, headers, content)

        if status == 401:
            raise SecurityError('Not authorized to set bucket properties.')
        elif status != 204:
            raise RiakError('Error setting bucket properties.')
        return True