Пример #1
0
    def kms_request(self, kms_context):
        """Complete a KMS request.

        :Parameters:
          - `kms_context`: A :class:`MongoCryptKmsContext`.

        :Returns:
          None
        """
        endpoint = kms_context.endpoint
        message = kms_context.message
        host, port = parse_host(endpoint, _HTTPS_PORT)
        # Enable strict certificate verification, OCSP, match hostname, and
        # SNI using the system default CA certificates.
        ctx = get_ssl_context(
            None,  # certfile
            None,  # keyfile
            None,  # passphrase
            None,  # ca_certs
            CERT_REQUIRED,  # cert_reqs
            None,  # crlfile
            True,  # match_hostname
            True)  # check_ocsp_endpoint
        opts = PoolOptions(connect_timeout=_KMS_CONNECT_TIMEOUT,
                           socket_timeout=_KMS_CONNECT_TIMEOUT,
                           ssl_context=ctx)
        conn = _configured_socket((host, port), opts)
        try:
            conn.sendall(message)
            while kms_context.bytes_needed > 0:
                data = conn.recv(kms_context.bytes_needed)
                kms_context.feed(data)
        finally:
            conn.close()
Пример #2
0
def _parse_ssl_options(options):
    """Parse ssl options."""
    use_ssl = options.get('ssl')
    if use_ssl is not None:
        validate_boolean('ssl', use_ssl)

    certfile = options.get('ssl_certfile')
    keyfile = options.get('ssl_keyfile')
    passphrase = options.get('ssl_pem_passphrase')
    ca_certs = options.get('ssl_ca_certs')
    cert_reqs = options.get('ssl_cert_reqs')
    match_hostname = options.get('ssl_match_hostname', True)
    crlfile = options.get('ssl_crlfile')

    ssl_kwarg_keys = [k for k in options
                      if k.startswith('ssl_') and options[k]]
    if use_ssl == False and ssl_kwarg_keys:
        raise ConfigurationError("ssl has not been enabled but the "
                                 "following ssl parameters have been set: "
                                 "%s. Please set `ssl=True` or remove."
                                 % ', '.join(ssl_kwarg_keys))

    if ssl_kwarg_keys and use_ssl is None:
        # ssl options imply ssl = True
        use_ssl = True

    if use_ssl is True:
        ctx = get_ssl_context(
            certfile, keyfile, passphrase, ca_certs, cert_reqs, crlfile)
        return ctx, match_hostname
    return None, match_hostname
Пример #3
0
def _parse_ssl_options(options):
    """Parse ssl options."""
    use_ssl = options.get('ssl')
    if use_ssl is not None:
        validate_boolean('ssl', use_ssl)

    certfile = options.get('ssl_certfile')
    keyfile = options.get('ssl_keyfile')
    ca_certs = options.get('ssl_ca_certs')
    cert_reqs = options.get('ssl_cert_reqs')
    match_hostname = options.get('ssl_match_hostname', True)

    ssl_kwarg_keys = [k for k in options
                      if k.startswith('ssl_') and options[k]]
    if use_ssl == False and ssl_kwarg_keys:
        raise ConfigurationError("ssl has not been enabled but the "
                                 "following ssl parameters have been set: "
                                 "%s. Please set `ssl=True` or remove."
                                 % ', '.join(ssl_kwarg_keys))

    if cert_reqs and not ca_certs:
        raise ConfigurationError("If `ssl_cert_reqs` is not "
                                 "`ssl.CERT_NONE` then you must "
                                 "include `ssl_ca_certs` to be able "
                                 "to validate the server.")

    if ssl_kwarg_keys and use_ssl is None:
        # ssl options imply ssl = True
        use_ssl = True

    if use_ssl is True:
        ctx = get_ssl_context(certfile, keyfile, ca_certs, cert_reqs)
        return ctx, match_hostname
    return None, match_hostname
Пример #4
0
def _parse_ssl_options(options):
    """Parse ssl options."""
    use_ssl = options.get('ssl')
    if use_ssl is not None:
        validate_boolean('ssl', use_ssl)

    certfile = options.get('ssl_certfile')
    keyfile = options.get('ssl_keyfile')
    passphrase = options.get('ssl_pem_passphrase')
    ca_certs = options.get('ssl_ca_certs')
    cert_reqs = options.get('ssl_cert_reqs')
    match_hostname = options.get('ssl_match_hostname', True)
    crlfile = options.get('ssl_crlfile')
    check_ocsp_endpoint = options.get('ssl_check_ocsp_endpoint', True)

    ssl_kwarg_keys = [
        k for k in options if k.startswith('ssl_') and options[k]
    ]
    if use_ssl is False and ssl_kwarg_keys:
        raise ConfigurationError("ssl has not been enabled but the "
                                 "following ssl parameters have been set: "
                                 "%s. Please set `ssl=True` or remove." %
                                 ', '.join(ssl_kwarg_keys))

    if ssl_kwarg_keys and use_ssl is None:
        # ssl options imply ssl = True
        use_ssl = True

    if use_ssl is True:
        ctx = get_ssl_context(certfile, keyfile, passphrase, ca_certs,
                              cert_reqs, crlfile, match_hostname,
                              check_ocsp_endpoint)
        return ctx, match_hostname
    return None, match_hostname
Пример #5
0
def _parse_ssl_options(options):
    """Parse ssl options."""
    use_tls = options.get("tls")
    if use_tls is not None:
        validate_boolean("tls", use_tls)

    certfile = options.get("tlscertificatekeyfile")
    passphrase = options.get("tlscertificatekeyfilepassword")
    ca_certs = options.get("tlscafile")
    crlfile = options.get("tlscrlfile")
    allow_invalid_certificates = options.get("tlsallowinvalidcertificates",
                                             False)
    allow_invalid_hostnames = options.get("tlsallowinvalidhostnames", False)
    disable_ocsp_endpoint_check = options.get("tlsdisableocspendpointcheck",
                                              False)

    enabled_tls_opts = []
    for opt in (
            "tlscertificatekeyfile",
            "tlscertificatekeyfilepassword",
            "tlscafile",
            "tlscrlfile",
    ):
        # Any non-null value of these options implies tls=True.
        if opt in options and options[opt]:
            enabled_tls_opts.append(opt)
    for opt in (
            "tlsallowinvalidcertificates",
            "tlsallowinvalidhostnames",
            "tlsdisableocspendpointcheck",
    ):
        # A value of False for these options implies tls=True.
        if opt in options and not options[opt]:
            enabled_tls_opts.append(opt)

    if enabled_tls_opts:
        if use_tls is None:
            # Implicitly enable TLS when one of the tls* options is set.
            use_tls = True
        elif not use_tls:
            # Error since tls is explicitly disabled but a tls option is set.
            raise ConfigurationError("TLS has not been enabled but the "
                                     "following tls parameters have been set: "
                                     "%s. Please set `tls=True` or remove." %
                                     ", ".join(enabled_tls_opts))

    if use_tls:
        ctx = get_ssl_context(
            certfile,
            passphrase,
            ca_certs,
            crlfile,
            allow_invalid_certificates,
            allow_invalid_hostnames,
            disable_ocsp_endpoint_check,
        )
        return ctx, allow_invalid_hostnames
    return None, allow_invalid_hostnames
    def test_wincertstore(self):
        if sys.platform != "win32":
            raise SkipTest("Only valid on Windows.")
        if hasattr(ssl, "SSLContext"):
            # SSLSocket doesn't provide ca_certs attribute on pythons
            # with SSLContext and SSLContext provides no information
            # about ca_certs.
            raise SkipTest("Can't test when SSLContext available.")
        if not ssl_support.HAVE_WINCERTSTORE:
            raise SkipTest("Need wincertstore to test wincertstore.")

        ctx = get_ssl_context(None, None, CA_PEM, ssl.CERT_REQUIRED)
        ssl_sock = ctx.wrap_socket(socket.socket())
        self.assertEqual(ssl_sock.ca_certs, CA_PEM)

        ctx = get_ssl_context(None, None, None, None)
        ssl_sock = ctx.wrap_socket(socket.socket())
        self.assertEqual(ssl_sock.ca_certs, ssl_support._WINCERTS.name)
Пример #7
0
    def test_wincertstore(self):
        if sys.platform != "win32":
            raise SkipTest("Only valid on Windows.")
        if hasattr(ssl, "SSLContext"):
            # SSLSocket doesn't provide ca_certs attribute on pythons
            # with SSLContext and SSLContext provides no information
            # about ca_certs.
            raise SkipTest("Can't test when SSLContext available.")
        if not ssl_support.HAVE_WINCERTSTORE:
            raise SkipTest("Need wincertstore to test wincertstore.")

        ctx = get_ssl_context(None, None, None, CA_PEM, ssl.CERT_REQUIRED, None)
        ssl_sock = ctx.wrap_socket(socket.socket())
        self.assertEqual(ssl_sock.ca_certs, CA_PEM)

        ctx = get_ssl_context(None, None, None, None, None, None)
        ssl_sock = ctx.wrap_socket(socket.socket())
        self.assertEqual(ssl_sock.ca_certs, ssl_support._WINCERTS.name)
    def test_certifi_support(self):
        if hasattr(ssl, "SSLContext"):
            # SSLSocket doesn't provide ca_certs attribute on pythons
            # with SSLContext and SSLContext provides no information
            # about ca_certs.
            raise SkipTest("Can't test when SSLContext available.")
        if not ssl_support.HAVE_CERTIFI:
            raise SkipTest("Need certifi to test certifi support.")

        have_wincertstore = ssl_support.HAVE_WINCERTSTORE
        # Force the test on Windows, regardless of environment.
        ssl_support.HAVE_WINCERTSTORE = False
        try:
            ctx = get_ssl_context(None, None, CA_PEM, ssl.CERT_REQUIRED)
            ssl_sock = ctx.wrap_socket(socket.socket())
            self.assertEqual(ssl_sock.ca_certs, CA_PEM)

            ctx = get_ssl_context(None, None, None, None)
            ssl_sock = ctx.wrap_socket(socket.socket())
            self.assertEqual(ssl_sock.ca_certs, ssl_support.certifi.where())
        finally:
            ssl_support.HAVE_WINCERTSTORE = have_wincertstore
Пример #9
0
    def test_certifi_support(self):
        if hasattr(ssl, "SSLContext"):
            # SSLSocket doesn't provide ca_certs attribute on pythons
            # with SSLContext and SSLContext provides no information
            # about ca_certs.
            raise SkipTest("Can't test when SSLContext available.")
        if not ssl_support.HAVE_CERTIFI:
            raise SkipTest("Need certifi to test certifi support.")

        have_wincertstore = ssl_support.HAVE_WINCERTSTORE
        # Force the test on Windows, regardless of environment.
        ssl_support.HAVE_WINCERTSTORE = False
        try:
            ctx = get_ssl_context(None, None, None, CA_PEM, ssl.CERT_REQUIRED, None)
            ssl_sock = ctx.wrap_socket(socket.socket())
            self.assertEqual(ssl_sock.ca_certs, CA_PEM)

            ctx = get_ssl_context(None, None, None, None, None, None)
            ssl_sock = ctx.wrap_socket(socket.socket())
            self.assertEqual(ssl_sock.ca_certs, ssl_support.certifi.where())
        finally:
            ssl_support.HAVE_WINCERTSTORE = have_wincertstore
Пример #10
0
    def test_system_certs_config_error(self):
        ctx = get_ssl_context(None, None, None, None, ssl.CERT_NONE, None)
        if ((sys.platform != "win32"
             and hasattr(ctx, "set_default_verify_paths"))
                or hasattr(ctx, "load_default_certs")):
            raise SkipTest(
                "Can't test when system CA certificates are loadable.")

        have_certifi = ssl_support.HAVE_CERTIFI
        have_wincertstore = ssl_support.HAVE_WINCERTSTORE
        # Force the test regardless of environment.
        ssl_support.HAVE_CERTIFI = False
        ssl_support.HAVE_WINCERTSTORE = False
        try:
            with self.assertRaises(ConfigurationError):
                MongoClient("mongodb://localhost/?ssl=true")
        finally:
            ssl_support.HAVE_CERTIFI = have_certifi
            ssl_support.HAVE_WINCERTSTORE = have_wincertstore
Пример #11
0
def check_ocsp(host, port, capath):
    ctx = get_ssl_context(
        None,  # certfile
        None,  # passphrase
        capath,  # ca_certs
        None,  # crlfile
        False,  # allow_invalid_certificates
        False,  # allow_invalid_hostnames
        False)  # disable_ocsp_endpoint_check

    # Ensure we're using pyOpenSSL.
    assert isinstance(ctx, SSLContext)

    s = socket.socket()
    s.connect((host, port))
    try:
        s = ctx.wrap_socket(s, server_hostname=host)
    finally:
        s.close()
    def test_system_certs_config_error(self):
        ctx = get_ssl_context(None, None, None, ssl.CERT_NONE)
        if ((sys.platform != "win32"
             and hasattr(ctx, "set_default_verify_paths"))
                or hasattr(ctx, "load_default_certs")):
            raise SkipTest(
                "Can't test when system CA certificates are loadable.")

        have_certifi = ssl_support.HAVE_CERTIFI
        have_wincertstore = ssl_support.HAVE_WINCERTSTORE
        # Force the test regardless of environment.
        ssl_support.HAVE_CERTIFI = False
        ssl_support.HAVE_WINCERTSTORE = False
        try:
            with self.assertRaises(ConfigurationError):
                MongoClient("mongodb://localhost/?ssl=true")
        finally:
            ssl_support.HAVE_CERTIFI = have_certifi
            ssl_support.HAVE_WINCERTSTORE = have_wincertstore
Пример #13
0
def check_ocsp(host, port, capath):
    ctx = get_ssl_context(
        None,  # certfile
        None,  # keyfile
        None,  # passphrase
        capath,
        CERT_REQUIRED,
        None,  # crlfile
        True,  # match_hostname
        True)  # check_ocsp_endpoint

    # Ensure we're using pyOpenSSL.
    assert isinstance(ctx, SSLContext)

    s = socket.socket()
    s.connect((host, port))
    try:
        s = ctx.wrap_socket(s, server_hostname=host)
    finally:
        s.close()
Пример #14
0
    def kms_request(self, kms_context):
        """Complete a KMS request.

        :Parameters:
          - `kms_context`: A :class:`MongoCryptKmsContext`.

        :Returns:
          None
        """
        endpoint = kms_context.endpoint
        message = kms_context.message
        ctx = get_ssl_context(None, None, None, None, None, None, True)
        opts = PoolOptions(connect_timeout=_KMS_CONNECT_TIMEOUT,
                           socket_timeout=_KMS_CONNECT_TIMEOUT,
                           ssl_context=ctx)
        with _configured_socket((endpoint, _HTTPS_PORT), opts) as conn:
            conn.sendall(message)
            while kms_context.bytes_needed > 0:
                data = conn.recv(kms_context.bytes_needed)
                kms_context.feed(data)
Пример #15
0
    def kms_request(self, kms_context):
        """Complete a KMS request.

        :Parameters:
          - `kms_context`: A :class:`MongoCryptKmsContext`.

        :Returns:
          None
        """
        endpoint = kms_context.endpoint
        message = kms_context.message
        provider = kms_context.kms_provider
        ctx = self.opts._kms_ssl_contexts.get(provider)
        if ctx is None:
            # Enable strict certificate verification, OCSP, match hostname, and
            # SNI using the system default CA certificates.
            ctx = get_ssl_context(
                None,  # certfile
                None,  # passphrase
                None,  # ca_certs
                None,  # crlfile
                False,  # allow_invalid_certificates
                False,  # allow_invalid_hostnames
                False,
            )  # disable_ocsp_endpoint_check
        opts = PoolOptions(
            connect_timeout=_KMS_CONNECT_TIMEOUT,
            socket_timeout=_KMS_CONNECT_TIMEOUT,
            ssl_context=ctx,
        )
        host, port = parse_host(endpoint, _HTTPS_PORT)
        conn = _configured_socket((host, port), opts)
        try:
            conn.sendall(message)
            while kms_context.bytes_needed > 0:
                data = conn.recv(kms_context.bytes_needed)
                if not data:
                    raise OSError("KMS connection closed")
                kms_context.feed(data)
        finally:
            conn.close()
Пример #16
0
    def test_cert_ssl_validation_hostname_matching(self):
        # Expects the server to be running with server.pem and ca.pem
        #
        #   --sslPEMKeyFile=/path/to/pymongo/test/certificates/server.pem
        #   --sslCAFile=/path/to/pymongo/test/certificates/ca.pem
        ctx = get_ssl_context(None, None, None, None, True, True, False)
        self.assertFalse(ctx.check_hostname)
        ctx = get_ssl_context(None, None, None, None, True, False, False)
        self.assertFalse(ctx.check_hostname)
        ctx = get_ssl_context(None, None, None, None, False, True, False)
        self.assertFalse(ctx.check_hostname)
        ctx = get_ssl_context(None, None, None, None, False, False, False)
        if _PY37PLUS or _HAVE_PYOPENSSL:
            self.assertTrue(ctx.check_hostname)
        else:
            self.assertFalse(ctx.check_hostname)

        response = self.client.admin.command(HelloCompat.LEGACY_CMD)

        with self.assertRaises(ConnectionFailure):
            connected(
                MongoClient('server',
                            ssl=True,
                            tlsCertificateKeyFile=CLIENT_PEM,
                            tlsAllowInvalidCertificates=False,
                            tlsCAFile=CA_PEM,
                            serverSelectionTimeoutMS=500,
                            **self.credentials))

        connected(
            MongoClient('server',
                        ssl=True,
                        tlsCertificateKeyFile=CLIENT_PEM,
                        tlsAllowInvalidCertificates=False,
                        tlsCAFile=CA_PEM,
                        tlsAllowInvalidHostnames=True,
                        serverSelectionTimeoutMS=500,
                        **self.credentials))

        if 'setName' in response:
            with self.assertRaises(ConnectionFailure):
                connected(
                    MongoClient('server',
                                replicaSet=response['setName'],
                                ssl=True,
                                tlsCertificateKeyFile=CLIENT_PEM,
                                tlsAllowInvalidCertificates=False,
                                tlsCAFile=CA_PEM,
                                serverSelectionTimeoutMS=500,
                                **self.credentials))

            connected(
                MongoClient('server',
                            replicaSet=response['setName'],
                            ssl=True,
                            tlsCertificateKeyFile=CLIENT_PEM,
                            tlsAllowInvalidCertificates=False,
                            tlsCAFile=CA_PEM,
                            tlsAllowInvalidHostnames=True,
                            serverSelectionTimeoutMS=500,
                            **self.credentials))
Пример #17
0
    def test_cert_ssl_validation_hostname_matching(self):
        # Expects the server to be running with server.pem and ca.pem
        #
        #   --sslPEMKeyFile=/path/to/pymongo/test/certificates/server.pem
        #   --sslCAFile=/path/to/pymongo/test/certificates/ca.pem
        ctx = get_ssl_context(None, None, None, None, ssl.CERT_NONE, None,
                              False, True)
        self.assertFalse(ctx.check_hostname)
        ctx = get_ssl_context(None, None, None, None, ssl.CERT_NONE, None,
                              True, True)
        self.assertFalse(ctx.check_hostname)
        ctx = get_ssl_context(None, None, None, None, ssl.CERT_REQUIRED, None,
                              False, True)
        self.assertFalse(ctx.check_hostname)
        ctx = get_ssl_context(None, None, None, None, ssl.CERT_REQUIRED, None,
                              True, True)
        if _PY37PLUS or _HAVE_PYOPENSSL:
            self.assertTrue(ctx.check_hostname)
        else:
            self.assertFalse(ctx.check_hostname)

        response = self.client.admin.command('ismaster')

        with self.assertRaises(ConnectionFailure):
            connected(
                MongoClient('server',
                            ssl=True,
                            ssl_certfile=CLIENT_PEM,
                            ssl_cert_reqs=ssl.CERT_REQUIRED,
                            ssl_ca_certs=CA_PEM,
                            serverSelectionTimeoutMS=500,
                            **self.credentials))

        connected(
            MongoClient('server',
                        ssl=True,
                        ssl_certfile=CLIENT_PEM,
                        ssl_cert_reqs=ssl.CERT_REQUIRED,
                        ssl_ca_certs=CA_PEM,
                        ssl_match_hostname=False,
                        serverSelectionTimeoutMS=500,
                        **self.credentials))

        if 'setName' in response:
            with self.assertRaises(ConnectionFailure):
                connected(
                    MongoClient('server',
                                replicaSet=response['setName'],
                                ssl=True,
                                ssl_certfile=CLIENT_PEM,
                                ssl_cert_reqs=ssl.CERT_REQUIRED,
                                ssl_ca_certs=CA_PEM,
                                serverSelectionTimeoutMS=500,
                                **self.credentials))

            connected(
                MongoClient('server',
                            replicaSet=response['setName'],
                            ssl=True,
                            ssl_certfile=CLIENT_PEM,
                            ssl_cert_reqs=ssl.CERT_REQUIRED,
                            ssl_ca_certs=CA_PEM,
                            ssl_match_hostname=False,
                            serverSelectionTimeoutMS=500,
                            **self.credentials))
Пример #18
0
    def test_cert_ssl_validation_hostname_matching(self):
        # Expects the server to be running with server.pem and ca.pem
        #
        #   --sslPEMKeyFile=/path/to/pymongo/test/certificates/server.pem
        #   --sslCAFile=/path/to/pymongo/test/certificates/ca.pem

        # Python > 2.7.9. If SSLContext doesn't have load_default_certs
        # it also doesn't have check_hostname.
        ctx = get_ssl_context(
            None, None, None, None, ssl.CERT_NONE, None, False)
        if hasattr(ctx, 'load_default_certs'):
            self.assertFalse(ctx.check_hostname)
            ctx = get_ssl_context(
                None, None, None, None, ssl.CERT_NONE, None, True)
            self.assertFalse(ctx.check_hostname)
            ctx = get_ssl_context(
                None, None, None, None, ssl.CERT_REQUIRED, None, False)
            self.assertFalse(ctx.check_hostname)
            ctx = get_ssl_context(
                None, None, None, None, ssl.CERT_REQUIRED, None, True)
            if _PY37PLUS:
                self.assertTrue(ctx.check_hostname)
            else:
                self.assertFalse(ctx.check_hostname)

        response = self.client.admin.command('ismaster')

        with self.assertRaises(ConnectionFailure):
            connected(MongoClient('server',
                                  ssl=True,
                                  ssl_certfile=CLIENT_PEM,
                                  ssl_cert_reqs=ssl.CERT_REQUIRED,
                                  ssl_ca_certs=CA_PEM,
                                  serverSelectionTimeoutMS=500,
                                  **self.credentials))

        connected(MongoClient('server',
                              ssl=True,
                              ssl_certfile=CLIENT_PEM,
                              ssl_cert_reqs=ssl.CERT_REQUIRED,
                              ssl_ca_certs=CA_PEM,
                              ssl_match_hostname=False,
                              serverSelectionTimeoutMS=500,
                              **self.credentials))

        if 'setName' in response:
            with self.assertRaises(ConnectionFailure):
                connected(MongoClient('server',
                                      replicaSet=response['setName'],
                                      ssl=True,
                                      ssl_certfile=CLIENT_PEM,
                                      ssl_cert_reqs=ssl.CERT_REQUIRED,
                                      ssl_ca_certs=CA_PEM,
                                      serverSelectionTimeoutMS=500,
                                      **self.credentials))

            connected(MongoClient('server',
                                  replicaSet=response['setName'],
                                  ssl=True,
                                  ssl_certfile=CLIENT_PEM,
                                  ssl_cert_reqs=ssl.CERT_REQUIRED,
                                  ssl_ca_certs=CA_PEM,
                                  ssl_match_hostname=False,
                                  serverSelectionTimeoutMS=500,
                                  **self.credentials))