Beispiel #1
0
 def getContext(self):
     context = SSL.Context(SSL.TLSv1_METHOD)
     context.set_options(0x00020000)#SSL_OP_NO_COMPRESSION
     context.set_options(SSL.OP_DONT_INSERT_EMPTY_FRAGMENTS)
     context.set_options(SSL.OP_TLS_BLOCK_PADDING_BUG)
     return context
Beispiel #2
0
def get_ssl_context(method=SSL_METHOD):
    # One of: One of SSLv2_METHOD, SSLv3_METHOD, SSLv23_METHOD, or TLSv1_METHOD
    if openssl_import_error:
        raise openssl_import_error  # pylint: disable=raising-bad-type
    return SSL.Context(method)
Beispiel #3
0
 def __init__(self, config):
     self._context = SSL.Context(SSL.SSLv23_METHOD)
     self.configure_context(self._context, config)
Beispiel #4
0
def _create_ssl_context(
    method: int = DEFAULT_METHOD,
    options: int = DEFAULT_OPTIONS,
    ca_path: str = None,
    ca_pemfile: str = None,
    cipher_list: str = None,
    alpn_protos: typing.Iterable[bytes] = None,
    alpn_select=None,
    alpn_select_callback: typing.Callable[[typing.Any, typing.Any],
                                          bytes] = None,
    verify: int = SSL.VERIFY_PEER,
    verify_callback: typing.Optional[typing.Callable[
        [SSL.Connection, SSL.X509, int, int, bool], bool]] = None,
) -> SSL.Context:
    """
    Creates an SSL Context.

    :param method: One of SSLv2_METHOD, SSLv3_METHOD, SSLv23_METHOD, TLSv1_METHOD, TLSv1_1_METHOD, or TLSv1_2_METHOD
    :param options: A bit field consisting of OpenSSL.SSL.OP_* values
    :param verify: A bit field consisting of OpenSSL.SSL.VERIFY_* values
    :param ca_path: Path to a directory of trusted CA certificates prepared using the c_rehash tool
    :param ca_pemfile: Path to a PEM formatted trusted CA certificate
    :param cipher_list: A textual OpenSSL cipher list, see https://www.openssl.org/docs/apps/ciphers.html
    :rtype : SSL.Context
    """
    try:
        context = SSL.Context(method)
    except ValueError:
        method_name = METHOD_NAMES.get(method, "unknown")
        raise exceptions.TlsException(
            "SSL method \"%s\" is most likely not supported "
            "or disabled (for security reasons) in your libssl. "
            "Please refer to https://github.com/mitmproxy/mitmproxy/issues/1101 "
            "for more details." % method_name)

    # Options (NO_SSLv2/3)
    if options is not None:
        context.set_options(options)

    # Verify Options (NONE/PEER and trusted CAs)
    if verify is not None:
        context.set_verify(verify, verify_callback)
        if ca_path is None and ca_pemfile is None:
            ca_pemfile = certifi.where()
        try:
            context.load_verify_locations(ca_pemfile, ca_path)
        except SSL.Error:
            raise exceptions.TlsException(
                "Cannot load trusted certificates ({}, {}).".format(
                    ca_pemfile, ca_path))

    # Workaround for
    # https://github.com/pyca/pyopenssl/issues/190
    # https://github.com/mitmproxy/mitmproxy/issues/472
    # Options already set before are not cleared.
    context.set_mode(SSL._lib.SSL_MODE_AUTO_RETRY)

    # Cipher List
    if cipher_list:
        try:
            context.set_cipher_list(cipher_list.encode())
        except SSL.Error as v:
            raise exceptions.TlsException(
                "SSL cipher specification error: %s" % str(v))

    # SSLKEYLOGFILE
    if log_master_secret:
        context.set_info_callback(log_master_secret)

    if alpn_protos is not None:
        # advertise application layer protocols
        context.set_alpn_protos(alpn_protos)
    elif alpn_select is not None and alpn_select_callback is None:
        # select application layer protocol
        def alpn_select_callback(conn_, options):
            if alpn_select in options:
                return bytes(alpn_select)
            else:  # pragma: no cover
                return options[0]

        context.set_alpn_select_callback(alpn_select_callback)
    elif alpn_select_callback is not None and alpn_select is None:
        if not callable(alpn_select_callback):
            raise exceptions.TlsException(
                "ALPN error: alpn_select_callback must be a function.")
        context.set_alpn_select_callback(alpn_select_callback)
    elif alpn_select_callback is not None and alpn_select is not None:
        raise exceptions.TlsException(
            "ALPN error: only define alpn_select (string) OR alpn_select_callback (function)."
        )

    return context
 def test02_fetch_from_url(self):
     config = Configuration(SSL.Context(SSL.TLSv1_2_METHOD), True)
     res = fetch_from_url(Constants.TEST_URI, config)
     self.assertTrue(res)
Beispiel #6
0
 def _test_openssl(self):
     '''
     Run a test with openssl to detect any MITM proxies
     '''
     success = True
     hostname = urlparse(self.base_url).netloc.split(':')
     sock = socket.socket()
     sock.setblocking(1)
     if self.proxies:
         connect_str = 'CONNECT {0} HTTP/1.0\r\n'.format(hostname[0])
         if self.proxy_auth:
             connect_str += 'Proxy-Authorization: {0}\r\n'.format(self.proxy_auth)
         connect_str += '\r\n'
         proxy = urlparse(self.proxies['https']).netloc.split(':')
         try:
             sock.connect((proxy[0], int(proxy[1])))
         except Exception as e:
             logger.debug(e)
             logger.error('Failed to connect to proxy %s. Connection refused.', self.proxies['https'])
             return False
         sock.send(connect_str)
         res = sock.recv(4096)
         if '200 Connection established' not in res:
             logger.error('Failed to connect to %s. Invalid hostname.', self.base_url)
             return False
     else:
         try:
             sock.connect((hostname[0], 443))
         except socket.gaierror:
             logger.error('Error: Failed to connect to %s. Invalid hostname.', self.base_url)
             return False
     ctx = SSL.Context(SSL.TLSv1_METHOD)
     if type(self.cert_verify) is not bool:
         if os.path.isfile(self.cert_verify):
             ctx.load_verify_locations(self.cert_verify, None)
         else:
             logger.error('Error: Invalid cert path: %s', self.cert_verify)
             return False
     ctx.set_verify(SSL.VERIFY_PEER, self._verify_check)
     ssl_conn = SSL.Connection(ctx, sock)
     ssl_conn.set_connect_state()
     try:
         # output from verify generated here
         ssl_conn.do_handshake()
         # print cert chain
         certs = self.cert_chain[1]
         # put them in the right order
         certs.reverse()
         logger.debug('---\nCertificate chain')
         for depth, c in enumerate(certs):
             logger.debug(self._generate_cert_str(c.get_subject(),
                                                  str(depth) + ' s :/'))
             logger.debug(self._generate_cert_str(c.get_issuer(),
                                                  '  i :/'))
         # print server cert
         server_cert = ssl_conn.get_peer_certificate()
         logger.debug('---\nServer certificate')
         logger.debug(crypto.dump_certificate(crypto.FILETYPE_PEM, server_cert))
         logger.debug(self._generate_cert_str(server_cert.get_subject(), 'subject=/'))
         logger.debug(self._generate_cert_str(server_cert.get_issuer(), 'issuer=/'))
         logger.debug('---')
     except SSL.Error as e:
         logger.debug('SSL error: %s', e)
         success = False
         logger.error('Certificate chain test failed!')
     ssl_conn.shutdown()
     ssl_conn.close()
     if self.cert_chain[0]:
         logger.error('Certificate chain test failed!  Self '
                      'signed certificate detected in chain')
     return success and not self.cert_chain[0]
Beispiel #7
0
    def _create_ssl_context(self,
                            enable_tls=False,
                            encrypt_only=False,
                            cafile=None,
                            capath=None,
                            keyfile=None,
                            keyfile_password=None,
                            certfile=None,
                            protocols=None,
                            cipher_suite=None):

        if not enable_tls:
            return
        method, protocols_to_disable = self._parse_protocols(protocols)
        self.ctx = SSL.Context(method)
        self.ctx = self._set_context_options(self.ctx, protocols_to_disable)
        if encrypt_only:
            self.ctx.set_verify(SSL.VERIFY_NONE, self._verify_none_cb)
        else:
            self.ctx.set_verify(SSL.VERIFY_PEER | SSL.VERIFY_CLIENT_ONCE,
                                self._verify_cb)
            if cafile or capath:
                try:
                    self.ctx.load_verify_locations(cafile, capath)
                except Exception as e:
                    path = ""

                    if cafile:
                        path = "cafile=%s" % (str(cafile))

                    if capath:
                        if path:
                            path += " and "
                        path += "capath=%s" % (str(capath))

                    raise Exception(
                        "Failed to load CA certificate from %s \n %s" %
                        (path, str(e)))

            if certfile:
                try:
                    self.ctx.use_certificate_chain_file(certfile)
                except Exception as e:
                    raise Exception(
                        "Failed to load certificate chain file %s \n %s" %
                        (certfile, str(e)))

            if keyfile:
                pkey = None
                pwd = None

                if keyfile_password:
                    try:
                        pwd = self._read_keyfile_password(keyfile_password)
                    except Exception as e:
                        raise Exception(
                            "Invalid keyfile_password {0} \n{1}".format(
                                keyfile_password, e))

                try:
                    pkey = crypto.load_privatekey(crypto.FILETYPE_PEM,
                                                  open(keyfile, 'rb').read(),
                                                  pwd)
                except IOError:
                    raise Exception(
                        "Unable to locate key file {}".format(keyfile))
                except crypto.Error:
                    raise Exception(
                        "Invalid key file or bad passphrase {}".format(
                            keyfile))
                except Exception as e:
                    raise Exception("Failed to load private key %s \n %s" %
                                    (keyfile, str(e)))

                if pkey is None:
                    raise Exception("Failed to load private key %s" % keyfile)

                try:
                    self.ctx.use_privatekey(pkey)
                except Exception as e:
                    raise Exception("Failed to load private key %s \n %s" %
                                    (keyfile, str(e)))

        if cipher_suite:
            self.ctx.set_cipher_list(cipher_suite)
Beispiel #8
0
    def _create_ssl_context(
        self,
        method=SSL_DEFAULT_METHOD,
        options=SSL_DEFAULT_OPTIONS,
        verify_options=SSL.VERIFY_NONE,
        ca_path=None,
        ca_pemfile=None,
        cipher_list=None,
        alpn_protos=None,
        alpn_select=None,
        alpn_select_callback=None,
    ):
        """
        Creates an SSL Context.

        :param method: One of SSLv2_METHOD, SSLv3_METHOD, SSLv23_METHOD, TLSv1_METHOD, TLSv1_1_METHOD, or TLSv1_2_METHOD
        :param options: A bit field consisting of OpenSSL.SSL.OP_* values
        :param verify_options: A bit field consisting of OpenSSL.SSL.VERIFY_* values
        :param ca_path: Path to a directory of trusted CA certificates prepared using the c_rehash tool
        :param ca_pemfile: Path to a PEM formatted trusted CA certificate
        :param cipher_list: A textual OpenSSL cipher list, see https://www.openssl.org/docs/apps/ciphers.html
        :rtype : SSL.Context
        """
        context = SSL.Context(method)
        # Options (NO_SSLv2/3)
        if options is not None:
            context.set_options(options)

        # Verify Options (NONE/PEER and trusted CAs)
        if verify_options is not None:

            def verify_cert(conn, x509, errno, err_depth, is_cert_verified):
                if not is_cert_verified:
                    self.ssl_verification_error = dict(errno=errno,
                                                       depth=err_depth)
                return is_cert_verified

            context.set_verify(verify_options, verify_cert)
            if ca_path is None and ca_pemfile is None:
                ca_pemfile = certifi.where()
            context.load_verify_locations(ca_pemfile, ca_path)

        # Workaround for
        # https://github.com/pyca/pyopenssl/issues/190
        # https://github.com/mitmproxy/mitmproxy/issues/472
        # Options already set before are not cleared.
        context.set_mode(SSL._lib.SSL_MODE_AUTO_RETRY)

        # Cipher List
        if cipher_list:
            try:
                context.set_cipher_list(cipher_list)

                # TODO: maybe change this to with newer pyOpenSSL APIs
                context.set_tmp_ecdh(
                    OpenSSL.crypto.get_elliptic_curve('prime256v1'))
            except SSL.Error as v:
                raise TlsException("SSL cipher specification error: %s" %
                                   str(v))

        # SSLKEYLOGFILE
        if log_ssl_key:
            context.set_info_callback(log_ssl_key)

        if HAS_ALPN:
            if alpn_protos is not None:
                # advertise application layer protocols
                context.set_alpn_protos(alpn_protos)
            elif alpn_select is not None and alpn_select_callback is None:
                # select application layer protocol
                def alpn_select_callback(conn_, options):
                    if alpn_select in options:
                        return bytes(alpn_select)
                    else:  # pragma no cover
                        return options[0]

                context.set_alpn_select_callback(alpn_select_callback)
            elif alpn_select_callback is not None and alpn_select is None:
                context.set_alpn_select_callback(alpn_select_callback)
            elif alpn_select_callback is not None and alpn_select is not None:
                raise TlsException(
                    "ALPN error: only define alpn_select (string) OR alpn_select_callback (method)."
                )

        return context
Beispiel #9
0
    def _create_ssl_context(
        self,
        method=SSL_DEFAULT_METHOD,
        options=SSL_DEFAULT_OPTIONS,
        verify_options=SSL.VERIFY_NONE,
        ca_path=None,
        ca_pemfile=None,
        cipher_list=None,
        alpn_protos=None,
        alpn_select=None,
        alpn_select_callback=None,
        sni=None,
    ):
        """
        Creates an SSL Context.

        :param method: One of SSLv2_METHOD, SSLv3_METHOD, SSLv23_METHOD, TLSv1_METHOD, TLSv1_1_METHOD, or TLSv1_2_METHOD
        :param options: A bit field consisting of OpenSSL.SSL.OP_* values
        :param verify_options: A bit field consisting of OpenSSL.SSL.VERIFY_* values
        :param ca_path: Path to a directory of trusted CA certificates prepared using the c_rehash tool
        :param ca_pemfile: Path to a PEM formatted trusted CA certificate
        :param cipher_list: A textual OpenSSL cipher list, see https://www.openssl.org/docs/apps/ciphers.html
        :rtype : SSL.Context
        """
        try:
            context = SSL.Context(method)
        except ValueError as e:
            method_name = ssl_method_names.get(method, "unknown")
            raise exceptions.TlsException(
                "SSL method \"%s\" is most likely not supported "
                "or disabled (for security reasons) in your libssl. "
                "Please refer to https://github.com/mitmproxy/mitmproxy/issues/1101 "
                "for more details." % method_name)

        # Options (NO_SSLv2/3)
        if options is not None:
            context.set_options(options)

        # Verify Options (NONE/PEER and trusted CAs)
        if verify_options is not None:

            def verify_cert(conn, x509, errno, err_depth, is_cert_verified):
                if not is_cert_verified:
                    self.ssl_verification_error = exceptions.InvalidCertificateException(
                        "Certificate Verification Error for {}: {} (errno: {}, depth: {})"
                        .format(
                            sni,
                            strutils.always_str(
                                SSL._ffi.string(
                                    SSL._lib.X509_verify_cert_error_string(
                                        errno)), "utf8"), errno, err_depth))
                return is_cert_verified

            context.set_verify(verify_options, verify_cert)
            if ca_path is None and ca_pemfile is None:
                ca_pemfile = certifi.where()
            try:
                context.load_verify_locations(ca_pemfile, ca_path)
            except SSL.Error:
                raise exceptions.TlsException(
                    "Cannot load trusted certificates ({}, {}).".format(
                        ca_pemfile, ca_path))

        # Workaround for
        # https://github.com/pyca/pyopenssl/issues/190
        # https://github.com/mitmproxy/mitmproxy/issues/472
        # Options already set before are not cleared.
        context.set_mode(SSL._lib.SSL_MODE_AUTO_RETRY)

        # Cipher List
        if cipher_list:
            try:
                context.set_cipher_list(cipher_list)
                context.set_tmp_ecdh(
                    OpenSSL.crypto.get_elliptic_curve('prime256v1'))
            except SSL.Error as v:
                raise exceptions.TlsException(
                    "SSL cipher specification error: %s" % str(v))

        # SSLKEYLOGFILE
        if log_ssl_key:
            context.set_info_callback(log_ssl_key)

        if HAS_ALPN:
            if alpn_protos is not None:
                # advertise application layer protocols
                context.set_alpn_protos(alpn_protos)
            elif alpn_select is not None and alpn_select_callback is None:
                # select application layer protocol
                def alpn_select_callback(conn_, options):
                    if alpn_select in options:
                        return bytes(alpn_select)
                    else:  # pragma no cover
                        return options[0]

                context.set_alpn_select_callback(alpn_select_callback)
            elif alpn_select_callback is not None and alpn_select is None:
                context.set_alpn_select_callback(alpn_select_callback)
            elif alpn_select_callback is not None and alpn_select is not None:
                raise exceptions.TlsException(
                    "ALPN error: only define alpn_select (string) OR alpn_select_callback (method)."
                )

        return context
Beispiel #10
0
def verify_cb(conn, cert, errnum, depth, ok):
    # This obviously has to be updated
    print 'Got certificate: %s' % cert.get_subject()
    return ok


if len(sys.argv) < 2:
    print 'Usage: python[2] server.py PORT'
    sys.exit(1)

dir = os.path.dirname(sys.argv[0])
if dir == '':
    dir = os.curdir

# Initialize context
ctx = SSL.Context(SSL.TLSv1_1_METHOD)
ctx.set_options(SSL.OP_NO_SSLv2)
ctx.set_verify(SSL.VERIFY_PEER | SSL.VERIFY_FAIL_IF_NO_PEER_CERT,
               verify_cb)  # Demand a certificate
ctx.use_privatekey_file(os.path.join(dir, 'server.pkey'))
ctx.use_certificate_file(os.path.join(dir, 'server.cert'))
ctx.load_verify_locations(os.path.join(dir, 'CA.cert'))

# Set up server
server = SSL.Connection(ctx, socket.socket(socket.AF_INET, socket.SOCK_STREAM))
server.bind(('', int(sys.argv[1])))
server.listen(3)
server.setblocking(0)

clients = {}
writers = {}
Beispiel #11
0
def run(config=None, plugin_providers=None, product_name='ajenti', dev_mode=False,
        debug_mode=False, autologin=False):
    """
    A global entry point for Ajenti.

    :param config: config file implementation instance to use
    :type  config: :class:`aj.config.BaseConfig`
    :param plugin_providers: list of plugin providers to load plugins from
    :type  plugin_providers: list(:class:`aj.plugins.PluginProvider`)
    :param str product_name: a product name to use
    :param bool dev_mode: enables dev mode (automatic resource recompilation)
    :param bool debug_mode: enables debug mode (verbose and extra logging)
    :param bool autologin: disables authentication and logs everyone in as the user running the panel. This is EXTREMELY INSECURE.
    """
    if config is None:
        raise TypeError('`config` can\'t be None')

    reload_module(sys)
    if hasattr(sys, 'setdefaultencoding'):
        sys.setdefaultencoding('utf8')

    aj.product = product_name
    aj.debug = debug_mode
    aj.dev = dev_mode
    aj.dev_autologin = autologin

    aj.init()
    aj.log.set_log_params(tag='master', master_pid=os.getpid())
    aj.context = Context()
    aj.config = config
    aj.plugin_providers = plugin_providers or []
    logging.info('Loading config from %s', aj.config)
    aj.config.load()
    aj.config.ensure_structure()

    if aj.debug:
        logging.warn('Debug mode')
    if aj.dev:
        logging.warn('Dev mode')

    try:
        locale.setlocale(locale.LC_ALL, '')
    except locale.Error:
        logging.warning('Couldn\'t set default locale')

    # install a passthrough gettext replacement since all localization is handled in frontend
    # and _() is here only for string extraction
    __builtins__['_'] = lambda x: x

    logging.info('Ajenti Core %s', aj.version)
    logging.info('Detected platform: %s / %s', aj.platform, aj.platform_string)

    # Load plugins
    PluginManager.get(aj.context).load_all_from(aj.plugin_providers)
    if len(PluginManager.get(aj.context)) == 0:
        logging.warn('No plugins were loaded!')

    if aj.config.data['bind']['mode'] == 'unix':
        path = aj.config.data['bind']['socket']
        if os.path.exists(path):
            os.unlink(path)
        listener = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
        try:
            listener.bind(path)
        except OSError:
            logging.error('Could not bind to %s', path)
            sys.exit(1)

    if aj.config.data['bind']['mode'] == 'tcp':
        host = aj.config.data['bind']['host']
        port = aj.config.data['bind']['port']
        listener = socket.socket(
            socket.AF_INET6 if ':' in host else socket.AF_INET, socket.SOCK_STREAM
        )
        if aj.platform not in ['freebsd', 'osx']:
            try:
                listener.setsockopt(socket.IPPROTO_TCP, socket.TCP_CORK, 1)
            except socket.error:
                logging.warn('Could not set TCP_CORK')
        listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        logging.info('Binding to [%s]:%s', host, port)
        try:
            listener.bind((host, port))
        except socket.error as e:
            logging.error('Could not bind: %s', str(e))
            sys.exit(1)

    # Fix stupid socketio bug (it tries to do *args[0][0])
    socket.socket.__getitem__ = lambda x, y: None

    listener.listen(10)

    gateway = GateMiddleware.get(aj.context)
    application = HttpRoot(HttpMiddlewareAggregator([gateway])).dispatch

    aj.server = SocketIOServer(
        listener,
        log=open(os.devnull, 'w'),
        application=application,
        handler_class=RequestHandler,
        policy_server=False,
        transports=[
            str('websocket'),
            str('flashsocket'),
            str('xhr-polling'),
            str('jsonp-polling'),
        ],
    )

    if aj.config.data['ssl']['enable'] and aj.config.data['bind']['mode'] == 'tcp':
        context = SSL.Context(SSL.TLSv1_2_METHOD)
        context.set_session_id(str(id(context)))
        context.set_options(SSL.OP_NO_SSLv2 | SSL.OP_NO_SSLv3 | SSL.OP_NO_TLSv1 | SSL.OP_NO_TLSv1_1)
        context.set_cipher_list('ALL:!ADH:!EXP:!LOW:!RC2:!3DES:!SEED:!RC4:+HIGH:+MEDIUM')

        certificate = crypto.load_certificate(
            crypto.FILETYPE_PEM,
            open(aj.config.data['ssl']['certificate']).read()
        )
        private_key = crypto.load_privatekey(
            crypto.FILETYPE_PEM,
            open(aj.config.data['ssl']['certificate']).read()
        )

        context.use_certificate(certificate)
        context.use_privatekey(private_key)

        if aj.config.data['ssl']['client_auth']['enable']:
            # todo harden files
            logging.info('Enabling SSL client authentication')
            context.add_client_ca(certificate)
            context.get_cert_store().add_cert(certificate)
            verify_flags = SSL.VERIFY_PEER
            if aj.config.data['ssl']['client_auth']['force']:
                verify_flags |= SSL.VERIFY_FAIL_IF_NO_PEER_CERT
            context.set_verify(verify_flags, AuthenticationService.get(aj.context).client_certificate_callback)
            context.set_verify_depth(0)

        aj.server.ssl_args = {'server_side': True}
        aj.server.wrap_socket = lambda socket, **ssl: SSLSocket(context, socket)
        logging.info('SSL enabled')

    # auth.log
    try:
        syslog.openlog(
            ident=str(aj.product),
            facility=syslog.LOG_AUTH,
        )
    except:
        syslog.openlog(aj.product)

    def cleanup():
        if hasattr(cleanup, 'started'):
            return
        cleanup.started = True
        logging.info('Process %s exiting normally', os.getpid())
        gevent.signal(signal.SIGINT, lambda: None)
        gevent.signal(signal.SIGTERM, lambda: None)
        if aj.master:
            gateway.destroy()

        p = psutil.Process(os.getpid())
        for c in p.children(recursive=True):
            try:
                os.killpg(c.pid, signal.SIGTERM)
                os.killpg(c.pid, signal.SIGKILL)
            except OSError:
                pass

    def signal_handler():
        cleanup()
        sys.exit(0)

    gevent.signal(signal.SIGINT, signal_handler)
    gevent.signal(signal.SIGTERM, signal_handler)

    aj.server.serve_forever()

    if not aj.master:
        # child process, server is stopped, wait until killed
        gevent.wait()

    if hasattr(aj.server, 'restart_marker'):
        logging.warn('Restarting by request')
        cleanup()

        fd = 20  # Close all descriptors. Creepy thing
        while fd > 2:
            try:
                os.close(fd)
                logging.debug('Closed descriptor #%i', fd)
            except OSError:
                pass
            fd -= 1

        logging.warn('Will restart the process now')
        if '-d' in sys.argv:
            sys.argv.remove('-d')
        os.execv(sys.argv[0], sys.argv)
    else:
        if aj.master:
            logging.debug('Server stopped')
            cleanup()
Beispiel #12
0
from OpenSSL import SSL
import ssl
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.poolmanager import PoolManager

SSL.Context(SSL.SSLv2_METHOD
            )  # Noncompliant {{Change this code to use a stronger protocol.}}
#               ^^^^^^^^^^^^
# Keyword argument
SSL.Context(method=SSL.SSLv2_METHOD)  # Noncompliant
SSL.Context(SSL.TLSv1_2_METHOD)  # Compliant
SSL.Context(method=SSL.TLSv1_2_METHOD)  # Compliant

# ssl.SSLContext()
ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv2)  # Noncompliant
ctx = ssl.SSLContext(protocol=ssl.PROTOCOL_SSLv2)  # Noncompliant

# ssl.wrap_socket()
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_SSLv2)  # Noncompliant
#                                  ^^^^^^^^^^^^^^

# ssl.SSLContext()
ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)  # Compliant
ctx = ssl.SSLContext(protocol=ssl.PROTOCOL_TLSv1_2)  # Compliant

# ssl.wrap_socket()
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_TLSv1_2)  # Compliant

Beispiel #13
0
 def getContext(self):
     return SSL.Context(SSL.SSLv23_METHOD)
Beispiel #14
0
def main(
    args: List[str] = sys.argv[1:],
) -> None:
    if sys.platform == "win32":
        # Magic incantation to make a Windows 10 cmd.exe process color-related ANSI escape codes.
        os.system("")

    # TODO: we lazily import "det deploy" but in the future we'd want to lazily import everything.
    parser = make_parser()

    full_cmd, aliases = generate_aliases(deploy_cmd.name)
    is_deploy_cmd = len(args) > 0 and any(args[0] == alias for alias in [*aliases, full_cmd])
    if is_deploy_cmd:
        from determined.deploy.cli import args_description as deploy_args_description

        add_args(parser, [deploy_args_description])
    else:
        add_args(parser, all_args_description)

    try:
        argcomplete.autocomplete(parser)

        parsed_args = parser.parse_args(args)

        def die(message: str, always_print_traceback: bool = False) -> None:
            if always_print_traceback or debug_mode():
                import traceback

                traceback.print_exc(file=sys.stderr)

            parser.exit(1, colored(message + "\n", "red"))

        v = vars(parsed_args)
        if not v.get("func"):
            parser.print_usage()
            parser.exit(2, "{}: no subcommand specified\n".format(parser.prog))

        try:
            # For `det deploy`, skip interaction with master.
            if is_deploy_cmd:
                parsed_args.func(parsed_args)
                return

            # Configure the CLI's Cert singleton.
            certs.cli_cert = certs.default_load(parsed_args.master)

            try:
                check_version(parsed_args)
            except requests.exceptions.SSLError:
                # An SSLError usually means that we queried a master over HTTPS and got an untrusted
                # cert, so allow the user to store and trust the current cert. (It could also mean
                # that we tried to talk HTTPS on the HTTP port, but distinguishing that based on the
                # exception is annoying, and we'll figure that out in the next step anyway.)
                addr = api.parse_master_address(parsed_args.master)
                check_not_none(addr.hostname)
                check_not_none(addr.port)
                try:
                    ctx = SSL.Context(SSL.TLSv1_2_METHOD)
                    conn = SSL.Connection(ctx, socket.socket())
                    conn.set_tlsext_host_name(cast(str, addr.hostname).encode())
                    conn.connect(cast(Sequence[Union[str, int]], (addr.hostname, addr.port)))
                    conn.do_handshake()
                    cert_pem_data = "".join(
                        crypto.dump_certificate(crypto.FILETYPE_PEM, cert).decode()
                        for cert in conn.get_peer_cert_chain()
                    )
                except crypto.Error:
                    die(
                        "Tried to connect over HTTPS but couldn't get a certificate from the "
                        "master; consider using HTTP"
                    )

                cert_hash = hashlib.sha256(ssl.PEM_cert_to_DER_cert(cert_pem_data)).hexdigest()
                cert_fingerprint = ":".join(chunks(cert_hash, 2))

                if not render.yes_or_no(
                    "The master sent an untrusted certificate chain with this SHA256 fingerprint:\n"
                    "{}\nDo you want to trust this certificate from now on?".format(
                        cert_fingerprint
                    )
                ):
                    die("Unable to verify master certificate")

                certs.CertStore(certs.default_store()).set_cert(parsed_args.master, cert_pem_data)
                # Reconfigure the CLI's Cert singleton, but preserve the certificate name.
                old_cert_name = certs.cli_cert.name
                certs.cli_cert = certs.Cert(cert_pem=cert_pem_data, name=old_cert_name)

                check_version(parsed_args)

            parsed_args.func(parsed_args)
        except KeyboardInterrupt as e:
            raise e
        except (api.errors.BadRequestException, api.errors.BadResponseException) as e:
            die("Failed to {}: {}".format(parsed_args.func.__name__, e))
        except api.errors.CorruptTokenCacheException:
            die(
                "Failed to login: Attempted to read a corrupted token cache. "
                "The store has been deleted; please try again."
            )
        except EnterpriseOnlyError as e:
            die(f"Determined Enterprise Edition is required for this functionality: {e}")
        except Exception:
            die("Failed to {}".format(parsed_args.func.__name__), always_print_traceback=True)
    except KeyboardInterrupt:
        # die() may not be defined yet.
        if debug_mode():
            import traceback

            traceback.print_exc(file=sys.stderr)

        print(colored("Interrupting...\n", "red"), file=sys.stderr)
        exit(3)
Beispiel #15
0
def verify_certificates(certificates: Dict[str, str]) -> (bool, str):
    """
    Verify certificates from 4 aspects:
    1. The CN of all public keys are equal.
    2. All the CN are generic domain names.
    3. Public key match private key.
    4. Private key is signed by CA.
    Args:
        certificates:
    Returns:
    """
    try:
        client_public_key = crypto.load_certificate(
            crypto.FILETYPE_PEM,
            b64decode(certificates.get('client/client.pem')))
        server_public_key = crypto.load_certificate(
            crypto.FILETYPE_PEM,
            b64decode(certificates.get('server/server.pem')))
        client_private_key = crypto.load_privatekey(
            crypto.FILETYPE_PEM,
            b64decode(certificates.get('client/client.key')))
        server_private_key = crypto.load_privatekey(
            crypto.FILETYPE_PEM,
            b64decode(certificates.get('server/server.key')))
        client_intermediate_ca = crypto.load_certificate(
            crypto.FILETYPE_PEM,
            b64decode(certificates.get('client/intermediate.pem')))
        server_intermediate_ca = crypto.load_certificate(
            crypto.FILETYPE_PEM,
            b64decode(certificates.get('server/intermediate.pem')))
        client_root_ca = crypto.load_certificate(
            crypto.FILETYPE_PEM,
            b64decode(certificates.get('client/root.pem')))
        server_root_ca = crypto.load_certificate(
            crypto.FILETYPE_PEM,
            b64decode(certificates.get('server/root.pem')))
    except crypto.Error as err:
        return False, 'Format of key or CA is invalid: {}'.format(err)

    if client_public_key.get_subject().CN != server_public_key.get_subject().CN:
        return False, 'Client and server public key CN mismatch'
    if not client_public_key.get_subject().CN.startswith('*.'):
        return False, 'CN of public key should be a generic domain name'

    try:
        client_context = SSL.Context(SSL.TLSv1_METHOD)
        client_context.use_certificate(client_public_key)
        client_context.use_privatekey(client_private_key)
        client_context.check_privatekey()

        server_context = SSL.Context(SSL.TLSv1_METHOD)
        server_context.use_certificate(server_public_key)
        server_context.use_privatekey(server_private_key)
        server_context.check_privatekey()
    except SSL.Error as err:
        return False, 'Key pair mismatch: {}'.format(err)

    try:
        client_store = crypto.X509Store()
        client_store.add_cert(client_root_ca)
        client_store.add_cert(client_intermediate_ca)
        crypto.X509StoreContext(client_store, client_public_key)\
            .verify_certificate()
    except crypto.X509StoreContextError as err:
        return False, 'Client key and CA mismatch: {}'.format(err)
    try:
        server_store = crypto.X509Store()
        server_store.add_cert(server_root_ca)
        server_store.add_cert(server_intermediate_ca)
        crypto.X509StoreContext(server_store, server_public_key)\
            .verify_certificate()
    except crypto.X509StoreContextError as err:
        return False, 'Server key and CA mismatch: {}'.format(err)

    return True, ''
Beispiel #16
0
 def getContext(self, *args, **kw):
     return SSL.Context(SSL.TLSv1_METHOD)
Beispiel #17
0
from OpenSSL import SSL

SSL.Context(SSL.SSLv3_METHOD)  # Noncompliant
Beispiel #18
0
def myproxy_logon_py(hostname,
                     username,
                     passphrase,
                     outfile,
                     lifetime=43200,
                     port=7512):
    """
    Function to retrieve a proxy credential from a MyProxy server
    
    Exceptions:  GetException, RetrieveProxyException
    """

    context = SSL.Context(SSL.SSLv3_METHOD)

    # disable for compatibility with myproxy server (er, globus)
    # globus doesn't handle this case, apparently, and instead
    # chokes in proxy delegation code
    context.set_options(0x00000800L)

    # connect to myproxy server
    if debuglevel(1): print "debug: connect to myproxy server"
    conn = SSL.Connection(context, socket.socket())
    conn.connect((hostname, port))

    # send globus compatibility stuff
    if debuglevel(1): print "debug: send globus compat byte"
    conn.write('0')

    # send get command
    if debuglevel(1): print "debug: send get command"
    cmd_get = CMD_GET % (username, passphrase, lifetime)
    conn.write(cmd_get)

    # process server response
    if debuglevel(1): print "debug: get server response"
    dat = conn.recv(8192)
    if debuglevel(1): print dat
    response, errortext = deserialize_response(dat)
    if response:
        raise GetException(errortext)
    else:
        if debuglevel(1): print "debug: server response ok"

    # generate and send certificate request
    # - The client will generate a public/private key pair and send a
    #   NULL-terminated PKCS#10 certificate request to the server.
    if debuglevel(1): print "debug: send cert request"
    certreq, privatekey = create_cert_req()
    conn.send(certreq)

    # process certificates
    # - 1 byte , number of certs
    dat = conn.recv(1)
    numcerts = ord(dat[0])

    # - n certs
    if debuglevel(1): print "debug: receive certs"
    dat = conn.recv(8192)
    if debuglevel(2):
        print "debug: dumping cert data to myproxy.dump"
        f = file('myproxy.dump', 'w')
        f.write(dat)
        f.close()

    # process server response
    if debuglevel(1): print "debug: get server response"
    resp = conn.recv(8192)
    response, errortext = deserialize_response(resp)
    if response:
        raise RetrieveProxyException(errortext)
    else:
        if debuglevel(1): print "debug: server response ok"

    # deserialize certs from received cert data
    pem_certs = deserialize_certs(dat)
    if len(pem_certs) != numcerts:
        print "Warning: %d certs expected, %d received" % (numcerts,
                                                           len(pem_certs))

    # write certs and private key to file
    # - proxy cert
    # - private key
    # - rest of cert chain
    if debuglevel(1): print "debug: write proxy and certs to", outfile
    if isinstance(outfile, str):
        f = file(outfile, 'w')
    else:
        f = outfile
    f.write(pem_certs[0])
    f.write(privatekey)
    for c in pem_certs[1:]:
        f.write(c)
    if isinstance(file, str):
        f.close()
Beispiel #19
0
 def __init__(self):
     self._context = SSL.Context(SSL.SSLv23_METHOD)
     self._context.set_verify(VERIFY_NONE, lambda *_: None)
Beispiel #20
0
 def getContext(self):
     context = SSL.Context(SSL.TLSv1_METHOD)
     context.set_options(SSL.OP_DONT_INSERT_EMPTY_FRAGMENTS)
     context.set_options(SSL.OP_TLS_BLOCK_PADDING_BUG)
     context.set_cipher_list("AES256-SHA")
     return context
Beispiel #21
0
def myproxy_logon(hostname,username,passphrase,outfile,lifetime=43200,port=7512):
    """
    Function to retrieve a proxy credential from a MyProxy server
    
    Exceptions:  GetException, RetrieveProxyException
    """
    
    context = SSL.Context(SSL.SSLv3_METHOD)
    
    # disable for compatibility with myproxy server (er, globus)
    # globus doesn't handle this case, apparently, and instead
    # chokes in proxy delegation code
    context.set_options(0x00000800L)
    
    # connect to myproxy server
    logger.debug("connect to myproxy server %s" %hostname)
    conn = SSL.Connection(context,socket.socket())
    conn.connect((hostname,port))
    
    # send globus compatibility stuff
    logger.debug("send globus compat byte")
    conn.write('0')

    # send get command
    logger.debug("send get command")
    cmd_get = CMD_GET % (username,passphrase,lifetime)
    conn.write(cmd_get)

    # process server response
    logger.debug("get server response")
    dat = conn.recv(8192)
    logger.debug("receive: %r" %dat)

    response,errortext = deserialize_response(dat)
    if response:
        logger.debug("error: " + errortext)
        raise GetException(errortext)
    else:
        logger.debug("server response ok")
    
    # generate and send certificate request
    # - The client will generate a public/private key pair and send a 
    #   NULL-terminated PKCS#10 certificate request to the server.
    logger.debug("send cert request")
    certreq,privatekey = create_cert_req()
    conn.send(certreq)

    # process certificates
    # - 1 byte , number of certs
    dat = conn.recv(1)
    numcerts = ord(dat[0])
    
    # - n certs
    logger.debug("receive certs")
    dat = conn.recv(8192)
    # if debuglevel(2):
    #     logger.debug('dumping cert data to "%s"' %settings.MYPROXY_DUMP_FILE)
    #     f = file(settings.MYPROXY_DUMP_FILE,'w')
    #     f.write(dat)
    #     f.close()

    # process server response
    logger.debug("get server response")
    resp = conn.recv(8192)
    response,errortext = deserialize_response(resp)
    if response:
        logger.debug("RetrieveProxyException " + errortext)
        raise RetrieveProxyException(errortext)
    else:
        logger.debug("server response ok")

    # deserialize certs from received cert data
    pem_certs = deserialize_certs(dat)
    if len(pem_certs) != numcerts:
        logger.debug("Warning: %d certs expected, %d received" % (numcerts,len(pem_certs)))

    # write certs and private key to file
    # - proxy cert
    # - private key
    # - rest of cert chain
    
    return dict(cert=pem_certs[0], key=privatekey, calist=pem_certs[1:])
Beispiel #22
0
 def getContext(self):
     ctx = SSL.Context(SSL.SSLv23_METHOD)
     ctx.use_certificate_file(config.SERVER_CERT_PATH)
     ctx.use_privatekey_file(config.SERVER_KEY_PATH)
     return ctx
Beispiel #23
0
 def test01_configuration(self):
     config = Configuration(SSL.Context(SSL.TLSv1_2_METHOD), True)
     self.assertTrue(config.ssl_context)
     self.assertEqual(config.debug, True)
Beispiel #24
0
    def check_rdp(host, username, password, domain, hashes = None):

       if hashes is not None:
           lmhash, nthash = hashes.split(':')
           lmhash = a2b_hex(lmhash)
           nthash = a2b_hex(nthash)

       else:
           lmhash = ''
           nthash = ''

       tpkt = TPKT()
       tpdu = TPDU()
       rdp_neg = RDP_NEG_REQ()
       rdp_neg['Type'] = TYPE_RDP_NEG_REQ
       rdp_neg['requestedProtocols'] = PROTOCOL_HYBRID | PROTOCOL_SSL
       tpdu['VariablePart'] = str(rdp_neg)
       tpdu['Code'] = TDPU_CONNECTION_REQUEST
       tpkt['TPDU'] = str(tpdu)
   
       s = socket.socket()
       s.connect((host,3389))
       s.sendall(str(tpkt))
       pkt = s.recv(8192)
       tpkt.fromString(pkt)
       tpdu.fromString(tpkt['TPDU'])
       cr_tpdu = CR_TPDU(tpdu['VariablePart'])
       if cr_tpdu['Type'] == TYPE_RDP_NEG_FAILURE:
           rdp_failure = RDP_NEG_FAILURE(tpdu['VariablePart'])
           rdp_failure.dump()
           logging.error("Server doesn't support PROTOCOL_HYBRID, hence we can't use CredSSP to check credentials")
           return
       else:
           rdp_neg.fromString(tpdu['VariablePart'])

       # Since we were accepted to talk PROTOCOL_HYBRID, below is its implementation

       # 1. The CredSSP client and CredSSP server first complete the TLS handshake, 
       # as specified in [RFC2246]. After the handshake is complete, all subsequent 
       # CredSSP Protocol messages are encrypted by the TLS channel. 
       # The CredSSP Protocol does not extend the TLS wire protocol. As part of the TLS 
       # handshake, the CredSSP server does not request the client's X.509 certificate 
       # (thus far, the client is anonymous). Also, the CredSSP Protocol does not require 
       # the client to have a commonly trusted certification authority root with the 
       # CredSSP server. Thus, the CredSSP server MAY use, for example, 
       # a self-signed X.509 certificate.

       # Switching to TLS now
       ctx = SSL.Context(SSL.TLSv1_METHOD)
       ctx.set_cipher_list('RC4')
       tls = SSL.Connection(ctx,s)
       tls.set_connect_state()
       tls.do_handshake()

       # If you want to use Python internal ssl, uncomment this and comment 
       # the previous lines
       #tls = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_TLSv1, ciphers='RC4')

       # 2. Over the encrypted TLS channel, the SPNEGO handshake between the client 
       # and server completes mutual authentication and establishes an encryption key 
       # that is used by the SPNEGO confidentiality services, as specified in [RFC4178]. 
       # All SPNEGO tokens as well as the underlying encryption algorithms are opaque to 
       # the calling application (the CredSSP client and CredSSP server). 
       # The wire protocol for SPNEGO is specified in [MS-SPNG].
       # The SPNEGO tokens exchanged between the client and the server are encapsulated 
       # in the negoTokens field of the TSRequest structure. Both the client and the 
       # server use this structure as many times as necessary to complete the SPNEGO 
       # exchange.<9>
       #
       # Note During this phase of the protocol, the OPTIONAL authInfo field is omitted 
       # from the TSRequest structure by the client and server; the OPTIONAL pubKeyAuth 
       # field is omitted by the client unless the client is sending the last SPNEGO token. 
       # If the client is sending the last SPNEGO token, the TSRequest structure MUST have 
       # both the negoToken and the pubKeyAuth fields filled in.

       # NTLMSSP stuff
       auth = ntlm.getNTLMSSPType1('','',True, use_ntlmv2 = True)

       ts_request = TSRequest()
       ts_request['NegoData'] = str(auth)

       tls.send(ts_request.getData())
       buff = tls.recv(4096)
       ts_request.fromString(buff)

   
       # 3. The client encrypts the public key it received from the server (contained 
       # in the X.509 certificate) in the TLS handshake from step 1, by using the 
       # confidentiality support of SPNEGO. The public key that is encrypted is the 
       # ASN.1-encoded SubjectPublicKey sub-field of SubjectPublicKeyInfo from the X.509 
       # certificate, as specified in [RFC3280] section 4.1. The encrypted key is 
       # encapsulated in the pubKeyAuth field of the TSRequest structure and is sent over 
       # the TLS channel to the server. 
       #
       # Note During this phase of the protocol, the OPTIONAL authInfo field is omitted 
       # from the TSRequest structure; the client MUST send its last SPNEGO token to the 
       # server in the negoTokens field (see step 2) along with the encrypted public key 
       # in the pubKeyAuth field.

       # Last SPNEGO token calculation
       #ntlmChallenge = ntlm.NTLMAuthChallenge(ts_request['NegoData'])
       type3, exportedSessionKey = ntlm.getNTLMSSPType3(auth, ts_request['NegoData'], username, password, domain, lmhash, nthash, use_ntlmv2 = True)

       # Get server public key
       server_cert =  tls.get_peer_certificate()
       pkey = server_cert.get_pubkey()
       dump = crypto.dump_privatekey(crypto.FILETYPE_ASN1, pkey)

       # Fix up due to PyOpenSSL lack for exporting public keys
       dump = dump[7:]
       dump = '\x30'+ asn1encode(dump)

       cipher = SPNEGOCipher(type3['flags'], exportedSessionKey)
       signature, cripted_key = cipher.encrypt(dump)
       ts_request['NegoData'] = str(type3)
       ts_request['pubKeyAuth'] = str(signature) + cripted_key

       try:
           # Sending the Type 3 NTLM blob
           tls.send(ts_request.getData())
           # The other end is waiting for the pubKeyAuth field, but looks like it's
           # not needed to check whether authentication worked.
           # If auth is unsuccessful, it throws an exception with the previous send().
           # If auth is successful, the server waits for the pubKeyAuth and doesn't answer 
           # anything. So, I'm sending garbage so the server returns an error. 
           # Luckily, it's a different error so we can determine whether or not auth worked ;)
           buff = tls.recv(1024)
       except Exception, err:
           if str(err).find("denied") > 0:
               logging.error("Access Denied")
           else:
               logging.error(err)
           return
Beispiel #25
0
 def test03_open_url(self):
     config = Configuration(SSL.Context(SSL.TLSv1_2_METHOD), True)
     res = open_url(Constants.TEST_URI, config)
     self.assertEqual(res[0], 200,
                      'open_url for %r failed' % Constants.TEST_URI)
Beispiel #26
0
 def cacheContext(self):
     ctx = SSL.Context(self.sslmethod)
     ctx.use_certificate_chain_file(self.certificateChainFileName)
     ctx.use_privatekey_file(self.privateKeyFileName)
     self._context = ctx
Beispiel #27
0
#!/usr/bin/env python
# Basic OpenSSL example - Chapter 15 - osslbasic.py

import socket, sys
from OpenSSL import SSL

# Create SSL context object
ctx = SSL.Context(SSL.SSLv23_METHOD)

print "Creating socket...",
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print "done."

# Create SSL connection object
ssl = SSL.Connection(ctx, s)

print "Establishing SSL...",
ssl.connect(('www.openssl.org', 443))
print "done."

print "Requesting document...",
ssl.sendall("GET / HTTP/1.0\r\n\r\n")
print "done."

while 1:
    try:
        buf = ssl.recv(4096)
    except SSL.ZeroReturnError:
        break
    sys.stdout.write(buf)
# Python Flask based Content Management System/Application - APIs Implementation

# Importing all necessary Python Flask libraries...
from flask import Flask, render_template, redirect, url_for, request
from flask_sqlalchemy import SQLAlchemy
from flask_bcrypt import Bcrypt
from flask_login import LoginManager
from flask_login import UserMixin
from flask_login import login_user
from OpenSSL import SSL

# Creating a flask app...
app = Flask(__name__)

#SSL Certificates to make the application as secure "HTTPS" instead of "HTTP"...
context = SSL.Context(SSL.TLSv1_2_METHOD)
#context.use_certificate('cert.pem')
#context.use_privatekey('key.pem')

# Initialising the environment as development (non-production) for testing purposes...
ENV = 'dev'

# Postgresql DB config details based on the environment...
# Postgresql DB config details for development environment...
if ENV == 'dev':
    app.debug = True
    #app.config['SQLALCHEMY_DATABASE_URI'] = f"postgresql://{user}:{password}@{host}:{port}/{database}"
    #app.config['SQLALCHEMY_DATABASE_URI'] = "postgresql://*****:*****@localhost:5432/postgres"
    app.config['SQLALCHEMY_DATABASE_URI'] = "postgresql://*****:*****@localhost/postgres"
# Postgresql DB config details for production environment...
else:
Beispiel #29
0
def check_rdp(host, port, username, password, domain, hashes=None, timeout=3):
    if hashes is not None:
        lmhash, nthash = hashes.split(':')
        lmhash = a2b_hex(lmhash)
        nthash = a2b_hex(nthash)

    else:
        lmhash = ''
        nthash = ''

    tpkt = TPKT()
    tpdu = TPDU()
    rdp_neg = RDP_NEG_REQ()
    rdp_neg['Type'] = TYPE_RDP_NEG_REQ
    rdp_neg['requestedProtocols'] = PROTOCOL_HYBRID | PROTOCOL_SSL
    tpdu['VariablePart'] = rdp_neg.getData()
    tpdu['Code'] = TDPU_CONNECTION_REQUEST
    tpkt['TPDU'] = tpdu.getData()

    s = socket.socket()
    s.settimeout(timeout)
    s.connect((host, port))
    s.sendall(tpkt.getData())
    pkt = s.recv(8192)
    tpkt.fromString(pkt)
    tpdu.fromString(tpkt['TPDU'])
    cr_tpdu = CR_TPDU(tpdu['VariablePart'])
    if cr_tpdu['Type'] == TYPE_RDP_NEG_FAILURE:
        rdp_failure = RDP_NEG_FAILURE(tpdu['VariablePart'])
        rdp_failure.dump()
        logger.debug(
            "Server doesn't support PROTOCOL_HYBRID, hence we can't use CredSSP to check credentials"
        )
        return False
    else:
        rdp_neg.fromString(tpdu['VariablePart'])

    # Since we were accepted to talk PROTOCOL_HYBRID, below is its implementation

    # 1. The CredSSP client and CredSSP server first complete the TLS handshake,
    # as specified in [RFC2246]. After the handshake is complete, all subsequent
    # CredSSP Protocol messages are encrypted by the TLS channel.
    # The CredSSP Protocol does not extend the TLS wire protocol. As part of the TLS
    # handshake, the CredSSP server does not request the client's X.509 certificate
    # (thus far, the client is anonymous). Also, the CredSSP Protocol does not require
    # the client to have a commonly trusted certification authority root with the
    # CredSSP server. Thus, the CredSSP server MAY use, for example,
    # a self-signed X.509 certificate.

    # Switching to TLS now
    ctx = SSL.Context(SSL.TLSv1_2_METHOD)
    ctx.set_cipher_list('RC4,AES')
    tls = SSL.Connection(ctx, s)
    tls.set_connect_state()
    tls.do_handshake()

    # If you want to use Python internal ssl, uncomment this and comment
    # the previous lines
    # tls = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_TLSv1, ciphers='RC4')

    # 2. Over the encrypted TLS channel, the SPNEGO handshake between the client
    # and server completes mutual authentication and establishes an encryption key
    # that is used by the SPNEGO confidentiality services, as specified in [RFC4178].
    # All SPNEGO tokens as well as the underlying encryption algorithms are opaque to
    # the calling application (the CredSSP client and CredSSP server).
    # The wire protocol for SPNEGO is specified in [MS-SPNG].
    # The SPNEGO tokens exchanged between the client and the server are encapsulated
    # in the negoTokens field of the TSRequest structure. Both the client and the
    # server use this structure as many times as necessary to complete the SPNEGO
    # exchange.<9>
    #
    # Note During this phase of the protocol, the OPTIONAL authInfo field is omitted
    # from the TSRequest structure by the client and server; the OPTIONAL pubKeyAuth
    # field is omitted by the client unless the client is sending the last SPNEGO token.
    # If the client is sending the last SPNEGO token, the TSRequest structure MUST have
    # both the negoToken and the pubKeyAuth fields filled in.

    # NTLMSSP stuff
    auth = ntlm.getNTLMSSPType1('', '', True, use_ntlmv2=True)

    ts_request = TSRequest()
    ts_request['NegoData'] = auth.getData()

    tls.send(ts_request.getData())
    buff = tls.recv(4096)
    ts_request.fromString(buff)

    # 3. The client encrypts the public key it received from the server (contained
    # in the X.509 certificate) in the TLS handshake from step 1, by using the
    # confidentiality support of SPNEGO. The public key that is encrypted is the
    # ASN.1-encoded SubjectPublicKey sub-field of SubjectPublicKeyInfo from the X.509
    # certificate, as specified in [RFC3280] section 4.1. The encrypted key is
    # encapsulated in the pubKeyAuth field of the TSRequest structure and is sent over
    # the TLS channel to the server.
    #
    # Note During this phase of the protocol, the OPTIONAL authInfo field is omitted
    # from the TSRequest structure; the client MUST send its last SPNEGO token to the
    # server in the negoTokens field (see step 2) along with the encrypted public key
    # in the pubKeyAuth field.

    # Last SPNEGO token calculation
    # ntlmChallenge = ntlm.NTLMAuthChallenge(ts_request['NegoData'])
    type3, exportedSessionKey = ntlm.getNTLMSSPType3(auth,
                                                     ts_request['NegoData'],
                                                     username,
                                                     password,
                                                     domain,
                                                     lmhash,
                                                     nthash,
                                                     use_ntlmv2=True)

    # Get server public key
    server_cert = tls.get_peer_certificate()
    pkey = server_cert.get_pubkey()
    dump = crypto.dump_privatekey(crypto.FILETYPE_ASN1, pkey)

    # Fix up due to PyOpenSSL lack for exporting public keys
    dump = dump[7:]
    dump = b'\x30' + asn1encode(dump)

    cipher = SPNEGOCipher(type3['flags'], exportedSessionKey)
    signature, cripted_key = cipher.encrypt(dump)
    ts_request['NegoData'] = type3.getData()
    ts_request['pubKeyAuth'] = signature.getData() + cripted_key

    try:
        # Sending the Type 3 NTLM blob
        tls.send(ts_request.getData())
        # The other end is waiting for the pubKeyAuth field, but looks like it's
        # not needed to check whether authentication worked.
        # If auth is unsuccessful, it throws an exception with the previous send().
        # If auth is successful, the server waits for the pubKeyAuth and doesn't answer
        # anything. So, I'm sending garbage so the server returns an error.
        # Luckily, it's a different error so we can determine whether or not auth worked ;)
        buff = tls.recv(1024)
    except Exception as err:
        if str(err).find("denied") > 0:
            logger.debug("Access Denied")
        else:
            logger.debug(err)
        return False

    # 4. After the server receives the public key in step 3, it first verifies that
    # it has the same public key that it used as part of the TLS handshake in step 1.
    # The server then adds 1 to the first byte representing the public key (the ASN.1
    # structure corresponding to the SubjectPublicKey field, as described in step 3)
    # and encrypts the binary result by using the SPNEGO encryption services.
    # Due to the addition of 1 to the binary data, and encryption of the data as a binary
    # structure, the resulting value may not be valid ASN.1-encoded values.
    # The encrypted binary data is encapsulated in the pubKeyAuth field of the TSRequest
    # structure and is sent over the encrypted TLS channel to the client.
    # The addition of 1 to the first byte of the public key is performed so that the
    # client-generated pubKeyAuth message cannot be replayed back to the client by an
    # attacker.
    #
    # Note During this phase of the protocol, the OPTIONAL authInfo and negoTokens
    # fields are omitted from the TSRequest structure.

    ts_request = TSRequest(buff)

    # Now we're decrypting the certificate + 1 sent by the server. Not worth checking ;)
    signature, plain_text = cipher.decrypt(ts_request['pubKeyAuth'][16:])

    # 5. After the client successfully verifies server authenticity by performing a
    # binary comparison of the data from step 4 to that of the data representing
    # the public key from the server's X.509 certificate (as specified in [RFC3280],
    # section 4.1), it encrypts the user's credentials (either password or smart card
    # PIN) by using the SPNEGO encryption services. The resulting value is
    # encapsulated in the authInfo field of the TSRequest structure and sent over
    # the encrypted TLS channel to the server.
    # The TSCredentials structure within the authInfo field of the TSRequest
    # structure MAY contain either a TSPasswordCreds or a TSSmartCardCreds structure,
    # but MUST NOT contain both.
    #
    # Note During this phase of the protocol, the OPTIONAL pubKeyAuth and negoTokens
    # fields are omitted from the TSRequest structure.
    tsp = TSPasswordCreds()
    tsp['domainName'] = domain
    tsp['userName'] = username
    tsp['password'] = password
    tsc = TSCredentials()
    tsc['credType'] = 1  # TSPasswordCreds
    tsc['credentials'] = tsp.getData()

    signature, cripted_creds = cipher.encrypt(tsc.getData())
    ts_request = TSRequest()
    ts_request['authInfo'] = signature.getData() + cripted_creds
    tls.send(ts_request.getData())
    tls.close()
    logger.debug("Access Granted")
    return True
Beispiel #30
0
	def cacheContext(self):
		ctx = SSL.Context(self.sslmethod)
		ctx.set_options(SSL.OP_NO_SSLv3|SSL.OP_NO_SSLv2)
		ctx.use_certificate_chain_file(self.certificateChainFileName)
		ctx.use_privatekey_file(self.privateKeyFileName)
		self._context = ctx